在使用Spring事务的过程中,有时会遇到事务失效的情况,那么什么情况下会出现事务失效,遇见这种情况又该如何定位解决呢。

事务失效的原因及解决方法

数据库不支持事务

这种情况很少出现,一般在一开始就能定位到的。比如Mysql的MyIsam存储引擎就不支持事务,因此如果使用MySQL要确保存储引擎是Innodb的。

Spring中未配置事务管理器

如果是springboot项目,可以加上注解@EnableTransactionManagement开启。
如果SpringMVC项目可以通过xml配置

1
2
3
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
<property ref="you_datasource" name="dataSource"/>
</bean>

方法不是public类型的

事务注解@Transaction可以作用在类、接口、public方法上,如果不是公共方法则事务不会生效,因为是基于代理实现的,私有方法不会被代理。

自身调用问题

同样不会走代理,事务注解也不会生效,详细见:Spring切面在对象内部方法调用中无效

异常类型错误

Spring事务回滚的机制是,对业务方法进行try-catch,当捕获到具体的异常的时候,才会回滚,默认RuntimeExceptionError异常回滚,可以通过

1
@Transactional(rollbackFor = {异常类型列表})

来指定什么异常回滚。

异常被业务自己处理了

如果在业务内部进行了try-catch,并没有throw出去异常,那么也不会进行回滚。

业务和Spring事务代码不在同一线程中

spring事务实现中使用了ThreadLocal,这就要求业务代码必须和spring事务的源码执行过程必须在一个线程中,才会受spring事务的控制。

1
2
3
4
5
6
7
8
9
10
11
@Transactional(rollbackFor = Exception.class)
public void insertOneDemo() {
UserInfo userInfo = new UserInfo();
// 在一个新的线程中事务操作
new Thread(()->{userInfoDAO.insertOne(userInfo);
long l = Long.parseLong(userInfo.getUserType());
System.out.println(l);
}).start();

ThreadUtil.sleep(1000);
}