Spring事务什么情况下会失效
Spring事务什么情况下会失效
小吴顶呱呱-
在方法中捕获异常并没有抛出去
spring控制事务是基于AOP机制,基于AOP的环绕通知的方式,如果方法抛出了异常给Spring框架,就会进行事务回滚,如果我们利用try…catch捕获了异常,异常不会抛出,也就不会进行事务回滚。
-
非事务方法调用事务方法
在非事务方法内部调用事务方法,尽管这个方法上面加了@Transactional 注解开启了事务,但因为并不是代理对象调用此方法,而是直接调用了 this 对象的方法,所以事务也会失效。因为spring是通过aop的方式,对需要spring管理事务的bean生成了代理对象,然后通过代理对象拦截了目标方法的执行,在方法前后添加了事务的功能,所以必须通过代理对象调用目标方法的时候,事务才会起效。
假设有一个UserService类,其中包含一个事务方法saveUser()和一个非事务方法updateUser():
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class UserService {
private UserMapper userMapper;
public void saveUser(User user) {
userMapper.save(user);
}
public void updateUser(User user) {
user.setName("Updated Name");
saveUser(user); // 在非事务方法中调用事务方法
}
}在上面的例子中,updateUser()方法是一个非事务方法,它调用了saveUser()方法,而saveUser()方法是一个带有@Transactional注解的事务方法。
由于updateUser()方法直接调用了saveUser()方法,而不是通过代理对象调用,因此事务将会失效。
-
事务方法调用事务方法
针对上面的例子,为了解决这个问题,可以将updateUser()方法也设置为事务方法,以确保事务能够生效:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class UserService {
private UserMapper userMapper;
public void saveUser(User user) {
userMapper.save(user);
}
public void updateUser(User user) {
user.setName("Updated Name");
saveUser(user); // 在事务方法中调用事务方法
}
}通过将updateUser()方法也设置为事务方法,就可以确保事务能够在方法调用时生效。
这样确实能解决,但是这样有一个弊端,看下面代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class UserService {
private UserMapper userMapper;
public void saveUser(User user) {
userMapper.save(user);
}
public void updateUser(User user) {
user.setName("Updated Name");
saveUser(user); // 在事务方法中调用事务方法
}
}如代码所示,利用事务的传播机制想在updateUser上面利用注解开启一个事务,但是由于updateUser不是代理对象调用的,所以并不会成功开启新事务。
我们可以通过把自己注入到Spring容器中,然后通过自己调用要被事务管理的方法,或者使用 AopContext.currentProxy() 获取代理对象,然后通过代理对象来调用即可。
-
@Transactional注解标记的方法不是public
-
抛出的异常与rollbackFor指定的异常不匹配,默认@Transactional中rollbackFor指定的异常为RuntimeException,通过指定rollbackFor的异常类型,表示只当抛出该类型的异常时才回滚,当抛出其他类型异常则不回滚,事务也就失效。
1
2//比如配置发生空指针异常时候才回滚,而其他运行时异常事务就会失效
-
数据库存储引擎本身不支持事务,如Mysql的MyISAM 引擎
-
Spring事务的传播特性导致事务失效,比如NEVER、NOT_SUPPORTED
我们在使用@Transactional注解时,是可以指定propagation参数的。该参数的作用是指定事务的传播特性,spring 目前支持 7 种传播特性:
-
REQUIRED 如果当前上下文中存在事务,则加入该事务,如果不存在事务,则创建一个事务,这是默认的传播属性值。
-
SUPPORTS 如果当前上下文中存在事务,则支持事务加入事务,如果不存在事务,则使用非事务的方式执行。
-
MANDATORY 当前上下文中必须存在事务,否则抛出异常。
-
REQUIRES_NEW 每次都会新建一个事务,并且同时将上下文中的事务挂起,执行当前新建事务完成以后,上下文事务恢复再执行。
-
NOT_SUPPORTED 如果当前上下文中存在事务,则挂起当前事务,然后新的方法在没有事务的环境中执行。
-
NEVER 如果当前上下文中**存在事务,则抛出异常,**否则在无事务环境上执行代码。
-
NESTED 如果当前上下文中存在事务,则嵌套事务执行,如果不存在事务,则新建事务。
-