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
代理。