Spring 事务管理与 MyBatis 的整合

153 阅读3分钟

Spring事务管理通过事务管理器、AOP代理与MyBatis的SqlSessionTemplate协作,实现事务同步,保障数据一致性。

一、核心原理

Spring 事务管理与 MyBatis 的整合依赖于以下核心机制:

  1. 事务管理器(PlatformTransactionManager Spring 通过 DataSourceTransactionManager 管理基于 JDBC 的事务,绑定到数据源(DataSource)。
  2. 动态代理与 AOP 使用 @Transactional 注解时,Spring 通过 AOP 生成代理对象,拦截事务方法。
  3. MyBatis-Spring 适配器 SqlSessionTemplateSqlSessionFactoryBean 确保 MyBatis 的 SqlSession 生命周期与 Spring 事务同步。

二、整合流程分析

1. 配置数据源与 MyBatis 组件

关键配置项(以 application.properties 和 Java Config 为例):

# 数据源配置
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
​
# MyBatis 配置
mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.type-aliases-package=com.example.entity

Java 配置类

@Configuration
@EnableTransactionManagement // 启用事务管理
@MapperScan("com.example.mapper") // 扫描 Mapper 接口
public class MyBatisConfig {
​
    // 数据源(Spring Boot 自动配置)
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource() {
        return DataSourceBuilder.create().build();
    }
​
    // SqlSessionFactory(整合 MyBatis)
    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(dataSource);
        factory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));
        return factory.getObject();
    }
​
    // 事务管理器(绑定数据源)
    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}

2. 事务管理流程

以下是一个事务方法执行的完整流程:

(1) 方法调用入口
@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;
​
    @Transactional
    public void createUser(User user) {
        userMapper.insert(user);
        // 其他业务逻辑...
    }
}
(2) Spring AOP 拦截
  • 代理对象生成:Spring 容器为 UserService 创建代理对象(CGLIB 或 JDK 动态代理)。
  • 事务拦截器TransactionInterceptor 拦截 @Transactional 方法。
(3) 事务开启
  • 获取数据库连接: 事务管理器从数据源获取连接,并关闭自动提交(autoCommit=false)。
  • 绑定到当前线程: 连接和事务状态存储到 TransactionSynchronizationManager 的线程局部变量中。
(4) 执行 SQL 操作
  • Mapper 方法调用UserMapper.insert(user) 被代理对象调用,实际执行 SqlSessionTemplate 的数据库操作。
  • 复用同一连接SqlSessionTemplate 确保在同一事务中复用当前线程绑定的 SqlSession
(5) 事务提交/回滚
  • 正常提交: 方法执行完毕,若未抛出异常,事务管理器调用 commit()
  • 异常回滚: 若抛出 RuntimeException 或指定异常,事务管理器调用 rollback()
(6) 资源清理
  • 归还连接: 事务结束后,连接归还到连接池。
  • 清除线程绑定TransactionSynchronizationManager 清理当前线程的事务状态。

三、关键组件交互

组件职责
DataSource提供数据库连接池,由 Spring Boot 自动配置。
SqlSessionFactory创建 SqlSession,整合 MyBatis 的 SQL 映射配置。
SqlSessionTemplate线程安全的 SqlSession 实现,与 Spring 事务管理器协同工作。
DataSourceTransactionManager管理 JDBC 事务,控制连接的提交和回滚。
@Transactional声明事务边界,触发 AOP 代理和事务拦截器。

四、事务传播行为与隔离级别

  1. 传播行为(Propagation)

    • REQUIRED(默认) :若当前存在事务,则加入;否则新建事务。
    • REQUIRES_NEW:始终新建事务,挂起当前事务(若有)。
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void updateUser(User user) { ... }
    
  2. 隔离级别(Isolation)

    • READ_COMMITTED(默认) :避免脏读,允许不可重复读和幻读。
    • SERIALIZABLE:完全串行化,避免所有并发问题。
    @Transactional(isolation = Isolation.SERIALIZABLE)
    public void criticalOperation() { ... }
    

五、常见问题与解决方案

问题原因解决方案
事务不生效未启用 @EnableTransactionManagement在配置类添加 @EnableTransactionManagement
Mapper 接口未注入未正确配置 @MapperScan@Mapper检查包扫描路径,或直接在接口上添加 @Mapper
事务回滚失败非受检异常未触发回滚使用 @Transactional(rollbackFor = Exception.class) 指定回滚异常类型。
连接泄漏未正确关闭 SqlSession确保使用 SqlSessionTemplate(自动管理资源)。

六、总结

Spring 与 MyBatis 的事务整合通过以下核心机制实现:

  1. 事务管理器绑定数据源:通过 DataSourceTransactionManager 控制事务生命周期。
  2. AOP 动态代理:拦截 @Transactional 方法,统一管理事务边界。
  3. 线程局部变量(ThreadLocal) :确保同一事务内复用数据库连接。
  4. SqlSessionTemplate:封装 MyBatis 操作,与 Spring 事务无缝协作。

最佳实践

  • 使用 @EnableTransactionManagement@MapperScan 简化配置。
  • 通过 @TransactionalrollbackForpropagation 细化事务控制。
  • 结合连接池(如 HikariCP)优化性能,避免长事务。