Spring事务管理通过事务管理器、AOP代理与MyBatis的SqlSessionTemplate协作,实现事务同步,保障数据一致性。
一、核心原理
Spring 事务管理与 MyBatis 的整合依赖于以下核心机制:
- 事务管理器(
PlatformTransactionManager) Spring 通过DataSourceTransactionManager管理基于 JDBC 的事务,绑定到数据源(DataSource)。 - 动态代理与 AOP 使用
@Transactional注解时,Spring 通过 AOP 生成代理对象,拦截事务方法。 - MyBatis-Spring 适配器
SqlSessionTemplate和SqlSessionFactoryBean确保 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 代理和事务拦截器。 |
四、事务传播行为与隔离级别
-
传播行为(Propagation)
REQUIRED(默认) :若当前存在事务,则加入;否则新建事务。REQUIRES_NEW:始终新建事务,挂起当前事务(若有)。
@Transactional(propagation = Propagation.REQUIRES_NEW) public void updateUser(User user) { ... } -
隔离级别(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 的事务整合通过以下核心机制实现:
- 事务管理器绑定数据源:通过
DataSourceTransactionManager控制事务生命周期。 - AOP 动态代理:拦截
@Transactional方法,统一管理事务边界。 - 线程局部变量(ThreadLocal) :确保同一事务内复用数据库连接。
- SqlSessionTemplate:封装 MyBatis 操作,与 Spring 事务无缝协作。
最佳实践:
- 使用
@EnableTransactionManagement和@MapperScan简化配置。 - 通过
@Transactional的rollbackFor和propagation细化事务控制。 - 结合连接池(如 HikariCP)优化性能,避免长事务。