@Transcational使用
在单体式的SpringBoot项目中, 为了减少在业务代码中参杂事务相关代码, 我们一般使用@Transcational注解来在业务代码中添加事务功能, 但有几种情况下会导致注解失效.
1. 数据库引擎不支持事务
首先要知道, @Transcational注解的事务是必须要依赖本地事务的, 也就是说必须依赖数据库的事务. 以MySql为例, 我们主要使用的MySql数据库引擎有两种, 分别是MyISAM和InnoDB. 而MyISAM引擎是不支持事务的, 如果此时项目的数据表中使用了MyISAM引擎就会导致@Transcational注解的失效.
2. 数据源没有配置事务管理器
在我们的项目中, 可能会出现有多个数据源的情况, 也就是说项目中的数据来源有两个或多个. 此时就需要手动配置多个数据源的作用场景以及多个数据源的数据库配置,
@Primary
@Bean(name = "masterDataSource")
@Qualifier("masterDataSource")
@ConfigurationProperties(prefix = "spring.datasource.druid.master")
public DataSource masterDataSource() {
return new DruidDataSource();
}
@Bean(name = "readDataSource")
@Qualifier("readDataSource")
@ConfigurationProperties(prefix = "spring.datasource.druid.read")
public DataSource readDataSource() {
return new DruidDataSource();
}
上述配置了两个数据源, 分别是 masterDataSource 和 readDataSource. 多个数据源配置此处暂时不加入了, 后面有时间我们再另外写一篇文章详细说, 如果仅仅是在项目中配置这样的两个数据源, 在配置文件中添加了两个数据源的数据库配置, 此时如果使用@Transcational注解是不生效的, 因为此时两数据库都缺少食物管理器. 因为两个数据源都是我们手动注入的, 所以事务管理器也需要我们手动注入, 需要再添加以下配置:
/**
* 配置声明式事务管理器
*/
@Bean(name = "masterTransactionManager")
@Primary
public PlatformTransactionManager masterTransactionManager(@Qualifier("masterDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
同样的, 另外一个数据源也需要这样配置事务管理器, 事务功能才能生效.
3. 没有把相关类交给Spring管理
在SpringBoot的项目中, 为了简化开发的工作, 很多的配置都是通过注解的方式来实现, 移除了xml配置文件. 此时需要注意, 只有Spring容器中的对象才能使用Spring提供的注解, 所以在使用@Transcational注解时, 必须保证当前类已经在Spring容器中
4. @Transcational注解所修饰的方式不是public修饰的
@Transcational实现事务使用的方式是动态代理, 如果此时修饰的方法是private, 就会出现动态代理无法调用到原方法的问题, 所以如果修饰的方法不是public也会导致注解的失效. 如果要用在非 public 方法上, 可以开启 AspectJ 代理模式.
5. 在同一个类中互相调用的方法
@Transactional
public void method1(){
method2();
}
@Transactional
public void method2(){
//todo
}
6. 方法中出现的异常被try/catch捕获了
@Transactional
public void method1(){
try {
update();
} catch (Exception e) {
e.printStackTrace();
}
}
此时如果 update() 方法出现了异常, 而异常被try-catch代码块捕获, 则Transcational 会无法捕获到异常, 不会使事务回滚.
7. 抛出的异常类型不在@Transcational捕获的范围
在默认情况下, @Transcational注解只有捕获到RunTimeException类型的异常才会回滚事务, 而如果在使用的注解的方法中抛出了其他异常, 是不会使事务回滚的.
可以自行手动配置:
@Transactional(rollbackFor = Exception.class)
public void method1(){
try {
update();
} catch (Exception e) {
e.printStackTrace();
}
}
注意:
手动配置的异常类型仅限于Throwable类及其子类, 其余类型配置了也不会生效.