1. 概述
在使用Spring或者Spring Boot集成MyBatis时,允许MyBatis 参与到 Spring 的事务管理中,而不是给 MyBatis 创建一个新的专用事务管理器,借助了 Spring 中的 DataSourceTransactionManager 来实现事务管理。
一旦配置好了 Spring 的事务管理器,就可以在 Spring 中按你平时的方式来配置事务。并且支持 @Transactional 注解和 AOP 风格的配置。在事务处理期间,一个单独的 SqlSession 对象将会被创建和使用。当事务完成时,这个 session 会以合适的方式提交或回滚。
事务配置好了以后,Spring 将会透明地管理事务,这样在你的 DAO 类中就不需要额外的代码了。
2. 编程式事务管理
编程式事务:通过编程代码在业务逻辑时需要时自行实现,粒度更小。
MyBatis 的 SqlSession 提供几个方法来在代码中处理事务。但是当集成了Spring 时,你的 bean 将会注入由 Sprin 管理的 SqlSession 或映射器。也就是说,Spring 总是为你处理了事务。
不能在 Spring 管理的 SqlSession 上调用 SqlSession.commit(),SqlSession.rollback() 或 SqlSession.close() 方法。这样做就会抛出 UnsupportedOperationException 异常。在使用注入的映射器时,这些方法也不会暴露出来。
Spring Framework 提供了两种编程事务管理的方法,通过使用:
-
TransactionTemplate或TransactionalOperator。 -
TransactionManager实现类。
首先我们注入PlatformTransactionManager:
/**
* PlatformTransactionManager 编程式事务管理器
*/
@Bean
public PlatformTransactionManager platformTransactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
然后在执行SQL的代码中加入手动事务管理:
@Autowired
PlatformTransactionManager transactionManager;
public void test(String address) {
TransactionStatus txStatus = transactionManager.getTransaction(new DefaultTransactionDefinition());
try {
userMapper.update(address);
int i = 5 / 0;
} catch (Exception e) {
// 发生异常回滚事务
transactionManager.rollback(txStatus);
throw e;
}
// 没有异常,提交事务
transactionManager.commit(txStatus);
}
执行操作,发生异常,发现数据没有变化,事务回滚成功。
3. 声明式事务管理
大多数 Spring Framework 用户选择声明式事务管理。此选项对应用程序代码的影响最小,因此最符合非侵入式轻量级容器的理想。
只需要添加@EnableTransactionManagement开启事务管理,然后在方法上添加@Transactional注解,就可以开启声明式事务管理。
首先在配置类加上@EnableTransactionManagement注解,并声明DataSourceTransactionManager的Bean对象。
@Configuration
@MapperScan(basePackages = {"org.pearl.spring.mybatis.demo.dao"})
@EnableTransactionManagement
public class MyBatisConfig {
/**
* 注入SqlSessionFactoryBean
*/
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource());
return factoryBean.getObject();
}
/**
* 设置Druid数据源,配置相关属性
*/
@Bean
public DataSource dataSource() {
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setUrl("jdbc:mysql://127.0.0.1:3306/angel_admin?serverTimezone=Asia/Shanghai");
druidDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
druidDataSource.setUsername("root");
druidDataSource.setPassword("123456");
return druidDataSource;
}
@Bean
public DataSourceTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
}
然后直接在业务方法上加上 @Transactional注解。
@Transactional
public void test(String address) {
userMapper.update(address);
int i = 5 / 0;
}
执行操作,发生异常,发现数据没有变化,事务回滚成功。可以看到报错信息,有AOP和拦截器相关的类,说明@Transactional注解用到了AOP代理。