对于从事Java开发的小伙伴来说,spring事务应该是非常熟悉的;在某些业务场景下,同时有多张表的写入操作,为了确保原子性,我们一般都会使用spring事务;spring事务在大多数情况下都可以满足需求,但同时他也有很多坑会导致事务失效。
我列举以下几点看看
1.错误的访问权限
@Service
public class TestService {
@Autowired
private Mapper mapper;
@Transactional
private void test(Model model) {
mapper.insert(model);
}
}
因为 add() 方法的访问修饰符被定义成了 private,所以导致了事务失效,spring 要求被代理的方法必须是由 public 修饰的。
因为AbstractFallbackTransactionAttributeSource类的computeTransactionAttribute方法中有个判断,如果目标方法不是public,则TransactionAttribute返回null,即不支持事务。
2.方法被定义成 final
@Service
public class TestService {
@Autowired
private Mapper mapper;
@Transactional
public final void add(Model model) {
mapper.insert(model);
}
}
由于 add 方法被定义成 final ,这样导致了 spring 的 aop 动态代理生成的代理对象不能复写该方法,导致事务失效。
3.方法的内部调用
@Service
public class TestService {
@Autowired
private Mapper mapper;
@Transactional
public void test(Model model) {
mapper.insert(model);
update(model);
}
@Transactional
public void update(Model model) {
// doSomeThing();
}
}
我们看到在事务方法add中,直接调用事务方法updateStatus。从前面介绍的内容可以知道,updateStatus方法拥有事务的能力是因为spring aop生成代理了对象,但是这种方法直接调用了this对象的方法,所以updateStatus方法不会生成事务。
4.当前实体对象没有被spring管理
这种情况就不上代码了,简单来说就是没有加注解,像 service 层没有加上 @Service 注解等,没有交给 spring 管理 Bean 实例,所以也不会生成事务。
5.抛出了异常但是被自己捕获了
@Transactional
public void test(Model model) {
try {
mapper.insert(model);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
如图所示,方法抛出了异常被自己捕获了,又没有重新抛出。事务的 AOP 无法捕获异常,导致出现了异常事务无法回滚。
6.数据库默认存储引擎不支持事务
msql8以前的版本数据库引擎是支持myslam和innerdb的。我以前也用过,对应查多写少的单表操作,可能会把表的数据库引擎定义成myslam,这样可以提升查询效率。但是,要千万记得一件事情,myslam只支持表锁,并且不支持事务。所以,对这类表的写入操作事务会失效。
这是写的第一篇博客,就先简单介绍一下 spring 事务常见的几种失效常见,往后我会不断更新我在工作中碰到的一些 bug、技巧等;感谢小伙伴的支持!