下面我将详细讲解“spring声明式事务 @Transactional 不回滚的多种情况以及解决方案”。
一、@Transactional不回滚的多种情况
1.1 默认回滚规则
- 默认情况下,Spring会对所有运行时异常进行回滚。也就是说,只有在方法中抛出
RuntimeException
及其子类异常时,才会导致事务回滚。 - 对于受检异常(即继承自
Exception
的异常),Spring不会自动回滚。
1.2 编程式事务管理
- 在使用编程式事务管理时,如果没有手动设置任何异常回滚,则不会触发回滚。
- 如果手动设置回滚条件,但设置的异常类型不是运行时异常,则不会回滚。
1.3 同一个类中的方法调用
- 由于
@Transactional
是基于AOP实现的,因此同一个类中的方法调用,不会触发事务回滚。原因是在一个事务方法内部调用另外一个有@Transactional
注解的方法,Spring框架并不会再次开启一个新的事务,而是继续使用已经存在的事务。因此即使另一个方法抛出异常,也不会影响当前事务的提交或回滚。
1.4 异常被捕获的情况
- 如果事务方法抛出一个异常,但是该异常在被当前方法所捕获,而没有被抛到事务方法之外,这时事务并不会进行回滚。这是由于Spring事务管理是通过AOP实现的,只有在方法执行时抛出异常,才会被AOP的拦截器捕获到,才能进行事务回滚。
1.5 事务回滚后的异常被捕获
- 如果事务方法抛出一个异常导致事务回滚,但是该异常在后续代码中被捕获并处理了,而不是被抛出到上层调用方法,那么回滚不会被成功执行。在处理完异常后,后续代码会继续执行,而不是回滚到之前的状态。这时需要在异常处理中重新抛出异常,在上层调用方法中进行处理。
二、解决方案
2.1 修改默认回滚规则
- 可以使用
@Transactional
注解的rollbackFor
属性来指定异常回滚的类型,如@Transactional(rollbackFor = Exception.class)
,这样就可以把受检异常也包含进回滚的规则中,实现更加灵活的回滚控制。
2.2 手动开启新的事务
- 可以在方法中调用自己所在的类的另一个有
@Transactional
注解的方法时,通过Propagation.REQUIRES_NEW
参数来指定该方法必须开启新的事务,例如:
```java
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
@Transactional
public void updateUser(User user) {
userMapper.updateUser(user);
// 更新用户信息后需要往用户日志表中插入一行新纪录
this.insertUserLog(user);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void insertUserLog(User user) {
UserLog userLog = new UserLog();
userLog.setUserId(user.getUserId());
userLog.setOperateType("update");
userMapper.insertUserLog(userLog);
}
}
```
2.3 解决异常被捕获的情况
- 可以将捕获异常的代码改为抛出异常,或者通过
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()
来手动设置回滚状态。例如:
java
@Override
@Transactional
public void updateUser(User user) {
try {
userMapper.updateUser(user);
throw new RuntimeException("test");
} catch (Exception e) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
throw e;
}
}
2.4 解决事务回滚后的异常被捕获
- 可以通过
TransactionAspectSupport.currentTransactionStatus().hasRollbackOnly()
方法来判断当前事务是否已经回滚,如果已经回滚,则需要重新抛出异常,例如:
java
@Override
@Transactional
public void updateUser(User user) {
try {
userMapper.updateUser(user);
throw new RuntimeException("test");
} catch (Exception e) {
if (TransactionAspectSupport.currentTransactionStatus().hasRollbackOnly()) {
throw e;
}
// ...处理异常
}
}
好了,这就是关于“spring声明式事务 @Transactional 不回滚的多种情况以及解决方案”的完整攻略。希望对你有所帮助。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:spring声明式事务 @Transactional 不回滚的多种情况以及解决方案 - Python技术站