当前位置: 首页 > news >正文

spring和mybatis的整合

一、环境搭建与依赖管理
1. 依赖配置扩展

除了基础的Spring、MyBatis和数据库驱动,推荐添加以下依赖以增强功能:

<!-- Spring JDBC(事务管理依赖) -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.3.20</version>
</dependency>

<!-- 日志框架(推荐SLF4J + Logback) -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.36</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.11</version>
</dependency>

<!-- 测试支持 -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13.2</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.3.20</version>
    <scope>test</scope>
</dependency>
2. 多环境配置(开发、测试、生产)

通过Spring的Profile机制实现环境隔离:

<!-- applicationContext.xml -->
<beans profile="dev">
    <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
        <!-- 开发环境数据库配置 -->
    </bean>
</beans>

<beans profile="prod">
    <bean id="dataSource" class="com.zaxxer.HikariDataSource">
        <!-- 生产环境数据库配置 -->
    </bean>
</beans>

激活方式:

  • JVM参数:-Dspring.profiles.active=dev

  • 代码中:System.setProperty("spring.profiles.active", "dev")

二、进阶配置技巧
1. JavaConfig配置方式(替代XML)

使用注解驱动配置更简洁:

@Configuration
@MapperScan("com.example.mapper") // 自动扫描Mapper接口
@EnableTransactionManagement      // 启用注解事务
public class MyBatisConfig {
    
    @Bean
    public DataSource dataSource() {
        HikariDataSource ds = new HikariDataSource();
        ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
        ds.setJdbcUrl("jdbc:mysql://localhost:3306/test_db");
        ds.setUsername("root");
        ds.setPassword("123456");
        return ds;
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(dataSource());
        factory.setMapperLocations(new PathMatchingResourcePatternResolver()
            .getResources("classpath:mapper/**/*.xml"));
        return factory.getObject();
    }

    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dataSource());
    }
}
2. 多数据源配置

在复杂项目中可能需要连接多个数据库:

@Configuration
public class MultiDataSourceConfig {
    
    @Bean(name = "primaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().type(HikariDataSource.class).build();
    }

    @Bean(name = "secondaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.secondary")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().type(HikariDataSource.class).build();
    }

    @Bean
    @Primary
    public SqlSessionFactory primarySqlSessionFactory(
            @Qualifier("primaryDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(dataSource);
        return factory.getObject();
    }

    @Bean
    public SqlSessionFactory secondarySqlSessionFactory(
            @Qualifier("secondaryDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(dataSource);
        return factory.getObject();
    }
}
三、MyBatis高阶特性实战
1. 动态SQL与复杂查询

在Mapper XML中编写动态SQL:

<select id="selectUsers" resultType="User">
    SELECT * FROM user
    <where>
        <if test="name != null">
            AND name LIKE CONCAT('%', #{name}, '%')
        </if>
        <if test="email != null">
            AND email = #{email}
        </if>
    </where>
    ORDER BY id DESC
</select>
2. 一级与二级缓存配置
  • 一级缓存:默认开启,作用域为SqlSession。

<mapper namespace="com.example.mapper.UserMapper">
    <cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/>
</mapper>
在Spring中需确保SqlSessionFactory的配置:
factory.setConfiguration(mybatisConfiguration()); // 设置全局配置

// 自定义Configuration
public Configuration mybatisConfiguration() {
    Configuration config = new Configuration();
    config.setCacheEnabled(true); // 启用二级缓存
    return config;
}
3. 自定义TypeHandler

处理复杂类型转换(如JSON字段与Java对象的映射):

@MappedTypes(UserDetail.class)
@MappedJdbcTypes(JdbcType.VARCHAR)
public class UserDetailTypeHandler extends BaseTypeHandler<UserDetail> {
    
    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, 
                                   UserDetail parameter, JdbcType jdbcType) {
        ps.setString(i, objectMapper.writeValueAsString(parameter));
    }

    @Override
    public UserDetail getNullableResult(ResultSet rs, String columnName) {
        return parseJson(rs.getString(columnName));
    }

    // 其他方法省略...
}

在MyBatis配置中注册:

<typeHandlers>
    <typeHandler handler="com.example.handler.UserDetailTypeHandler"/>
</typeHandlers>
四、性能优化与最佳实践
1. 连接池调优(HikariCP为例)
HikariConfig config = new HikariConfig();
config.setMaximumPoolSize(20);          // 最大连接数
config.setMinimumIdle(5);               // 最小空闲连接
config.setConnectionTimeout(30000);      // 连接超时时间(毫秒)
config.setIdleTimeout(600000);           // 空闲连接存活时间
config.setMaxLifetime(1800000);          // 连接最大生命周期
2. 批量操作提升性能

使用SqlSession的批量模式:

@Autowired
private SqlSessionFactory sqlSessionFactory;

public void batchInsertUsers(List<User> users) {
    try (SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH)) {
        UserMapper mapper = session.getMapper(UserMapper.class);
        for (User user : users) {
            mapper.insertUser(user);
        }
        session.commit(); // 手动提交
    }
}
3. SQL优化建议
  • 避免在循环中执行单条SQL

  • 使用<foreach>标签实现批量插入:

    <insert id="batchInsert">
        INSERT INTO user (name, email) VALUES
        <foreach item="user" collection="list" separator=",">
            (#{user.name}, #{user.email})
        </foreach>
    </insert>

五、测试与调试
1. 单元测试(Spring Test + JUnit)
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = MyBatisConfig.class)
public class UserMapperTest {
    
    @Autowired
    private UserMapper userMapper;

    @Test
    @Transactional // 测试后自动回滚
    public void testInsertUser() {
        User user = new User("Alice", "alice@example.com");
        userMapper.insertUser(user);
        assertNotNull(user.getId());
    }
}
2. SQL日志输出

配置Logback(logback.xml):

<logger name="com.example.mapper" level="DEBUG"/> <!-- Mapper接口日志 -->
<logger name="java.sql.Connection" level="DEBUG"/> <!-- SQL执行日志 -->
<logger name="org.mybatis" level="TRACE"/> <!-- MyBatis内部日志 -->
六、常见问题深度解析
1. 事务失效场景
  • 原因1:非public方法使用@Transactional

  • 原因2:自调用(同类方法内部调用)
    解决方案:通过AOP代理调用或使用AopContext.currentProxy()

2. 懒加载异常(LazyInitializationException)
  • 背景:在事务外访问延迟加载的关联对象

  • 解决方案

    • 使用OpenSessionInViewFilter(Web项目)

    • 在事务范围内提前加载所需数据(如JOIN FETCH

3. MyBatis映射字段丢失
  • 原因:数据库字段名与Java属性名不一致(如驼峰vs下划线)

  • 解决
    全局配置开启驼峰映射:

    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

相关文章:

  • Python的那些事第二十二篇:基于 Python 的 Django 框架在 Web 开发中的应用研究
  • sort快排
  • 包管理器-汇总介绍
  • 数据结构 day 07
  • 性格测评小程序06用户注册校验
  • PHP框架入门指南:从零构建现代Web应用
  • 中上211硕对嵌入式AI感兴趣,如何有效规划学习路径?
  • SpringMVC 请求参数接收
  • Unity-New Input System
  • 2-安装YIUI
  • AI语言模型的技术之争:DeepSeek与ChatGPT的架构与训练揭秘
  • 5G与物联网的协同发展:打造智能城市的未来
  • pip 与 conda 的故事
  • 5. 【.NET 8 实战--孢子记账--从单体到微服务--转向微服务】--微服务基础工具与技术--Nacos
  • resultType,jdbcType,parameterType区别
  • SQL-leetcode—1667. 修复表中的名字
  • Nginx 请求转发配置指南
  • Amazon Aurora:面向高吞吐量云原生关系型数据库的设计考虑
  • 性能测试工具
  • LLM之循环神经网络(RNN)
  • 前4个月全国新建商品房销售面积降幅收窄,房地产库存和新开工有所改善
  • 谷神星一号海射型遥五运载火箭发射成功
  • 十大券商看后市|A股指数有望进一步缓步推高,淡化短期波动
  • 肖钢:一季度证券业金融科技投资强度在金融各子行业中居首
  • 光明日报社副总编辑薄洁萍调任求是杂志社副总编辑
  • 网警打谣:传播涉刘国梁不实信息,2人被处罚