Spring事务回滚机制如何实现

一、Spring事务的概念及特性

1、事务是什么

事务是由一组操作(对数据库数据的处理,例如增、删、改等操作)组成的逻辑单元,要么全部执行成功,要么全部执行失败进行回滚。

2、事务的基本特性

(1)原子性:是一个不可分割的整体;

(2)一致性:事务执行完后,数据的一致性状态要么不变,要么转移到另外一个一致性状态;

(3)隔离性:并发事务之间是独立的;

(4)持久性:对数据的更改永久保存;

二、spring事务的管理、传播方式

1、管理方式

(1)编程式:调用beginTransaction()、commit()、rollback()等事务管理相关的方法

(2)声明式:通过注解或 XML 配置控制事务,推荐使用。

2、传播方式

(1)REQUIRED(默认):默认事务传播行为,存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。
(2)REQUIRE_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
(3)NESTED:如果当前存在事务,就嵌套当前事务中去执行,如果当前没有事务,那么就新建一个事务,类似 REQUIRE_NEW这个样一个传播行为。
(4)SUPPORTS:表示支持当前当前的事务,如果当前不存在事务,就以非事务的方式去执行。
(5)NOT_SUPPORT: 总是非事务地执行,并挂起任何存在的事务。
(6)MANDATORY:如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。
(7)NEVER:就是以非事务的方式来执行,如果存在事务则抛出一个异常

三、Spring事务的回滚机制

1、事务回滚触发条件

Spring事务的回滚主要基于异常的抛出:

(1)默认情况:

  • 捕获 unchecked Exception(如RuntimeException )或 Error 会导致事务回滚。
  • 捕获 Checked Exception(如 IOException)不会回滚,除非明确配置。

(2)可指定何种异常回滚

  • 使用 @Transactional(rollbackFor = Exception.class) 明确指定需要回滚的异常。

2、事务回滚实现流程

Spring 事务的回滚过程涉及以下关键步骤:

(1)Spring 扫描创建代理对象管理事务,即事务管理器。

(2)方法执行时,事务管理器开启事务。

(3)如果方法抛出指定异常,事务管理器调用数据库的回滚操作。

(4)如果方法成功执行,事务管理器提交事务。

四、Spring事务回滚示例

1、声明式事务回滚示例

(1)默认情况下回滚:

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

   @Autowired
    private  UserMapper userMapper;

    /**
     * 该方法使用@Transactional注解,表示该方法受事务管理。
     * 当RuntimeException抛出时,Spring 会自动回滚事务,insert操作不会持久化到数据库
     * @param user
     */
    @Override
    @Transactional
    public void insertUser(User user) {
        userMapper.insertUser(user);
        throw new RuntimeException("模拟异常");
    }
}

(2)指定回滚条件

默认情况下, checked exception 异常抛出不会引起事务回滚,但是可以通过 rollbackFor 属性显式指定需要回滚的异常类型 。

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

   @Autowired
    private  UserMapper userMapper;

    /**
     * 该方法使用@Transactional注解,表示该方法受事务管理。
     * 使用rollbackFor属性设置触发事务回滚异常类型
     * 当checked exception抛出时,Spring 会自动回滚事务,insert操作不会持久化到数据库
     * @param user
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertUser(User user) {
        userMapper.insertUser(user);
        throw new Exception("模拟异常");
    }
}

2、编程式事务回滚示例

Spring 提供了 TransactionTemplate 类,用于编程式管理事务。我们可以显式捕获异常并手动控制事务的提交或回滚。

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private  UserMapper userMapper;
    
    @Autowired
    private TransactionTemplate transactionTemplate;

 
   /**
     * 通过transactionTemplate声明事务逻辑
     * 当异常抛出时,通过transactionStatus.setRollbackOnly()手动触发事务回滚
     * @param user
     */
    @Override
    public void insertUser(User user) {
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
                try {
                    userMapper.insertUser(user);
                    throw new RuntimeException("模拟异常");
                }catch (Exception e){
                    //事务回滚
                    transactionStatus.setRollbackOnly();
                }

            }
        });
    }
}

五、事务回滚注意事项 

1、异常传播问题

当异常被捕获,但是异常未抛出时也不会触发事务回滚。

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private  UserMapper userMapper;
    
    @Autowired
    private TransactionTemplate transactionTemplate;

    
    @Override
    @Transactional
    public void insertUser(User user) {
        try {
            userMapper.insertUser(user);
            throw new RuntimeException("模拟异常");
        }catch (Exception e){
            //只捕获了异常,没有抛出,不会触发事务回滚
            log.error("事务回滚"+e.getMessage());
        }

    }
}

解决方法:捕获异常后重新抛出,或直接让异常传播。

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private  UserMapper userMapper;
    
    @Autowired
    private TransactionTemplate transactionTemplate;

   @Override
    @Transactional
    public void insertUser(User user) {
        try {
            userMapper.insertUser(user);
            throw new RuntimeException("模拟异常");
        }catch (Exception e){
            log.error("事务回滚"+e.getMessage());
            //触发事务回滚
            throw e;    
        }

    }

}

2、自调用导致事务失效

Spring 事务依赖 AOP 实现,如果同一个类中自调用事务方法,事务可能失效。

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private  UserMapper userMapper;
    
    @Autowired
    private TransactionTemplate transactionTemplate;

    @Autowired
    private IUserService userService;

    @Override
    @Transactional
    public void updateUser(User user) {
        userMapper.updateUser(user);
        //调用同一个类中的方法,会导致事务失效
        user.setName("调用方法");
        userService.insertUser(user);
    }

    @Override
    @Transactional
    public void insertUser(User user) {
        userMapper.insertUser(user);
        throw new RuntimeException("模拟异常");
    }
}

解决方法:

  • 将 insertUser移到另一个服务类,由代理对象调用。
  • 使用 @Transactional(propagation = Propagation.REQUIRES_NEW) 强制新建事务。

六、总结

使用Spring事务机制,可以使我们不再需要手动编写复杂的事务管理代码,而是通过简单的配置和注解来实现事务的管理,提高开发效率和代码的可维护性。同时,Spring的事务机制还支持多种数据访问框架,如JDBC、Hibernate、MyBatis等,对事务管理变得更加灵活和易用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值