SpringBoot:事务使用与回滚处理的简单示例与总结

在java中事务的使用在多表关联操作的业务处理中必不可少的。

注解式事务是使用最简单方便的,也是比较推荐的方式。下面介绍在SpringBoot中注解式事务的使用示例。

1.添加事务注解和事务的使用范围

以下是最简单是事务代码示例,其中taDAO和tbDAO是DAO层方法

 @Transactional
    public boolean updateInfo(HashMap<String, Object> map) {
        boolean flag=false;
        try {
            //update表A
            taDAO.update("1","小王");

            //update表B
            tbDAO.update("22","技术部");

            flag=true;
        } catch (Exception e) {
            logger.error(estr + e.toString());
            throw new RuntimeException();// 抛出RuntimeException异常给事务处理回滚
        }
        return flag;
    }

  问题:事务注解应该加在哪个层?

  在需要的方法和类上添加注解@Transactional上就可以。注意:添加在类上时,说明此类的public的方法都行事务管理。建议只在需要的方法上添加事务注解@Transactional

事务注解应添加在实现业务逻辑的Serviceimpl层,不要加到controller层或Service接口层。因为Serviceimpl层是具体业务的实现类,里面会调用到底层DAO的数据库

操作(事务提交和回滚的作用对象就是数据库操作),而controller层只是负责调用Service接口,Serviceimpl实现Service接口。所以在Serviceimpl层设置事务是最合适的。

2.事务提交与回滚

上面的代码中,添加完事务注解@Transactiona后,方法add就启用了事务管理。接下来用这个示例对事务的提交和回滚做一下说明。

以下是我测试的过程中验证以上这段代码能否自动回滚(读者也可以自己同步测试验证一下),

其中会结合网上的用法做补充说明(如:事务强调只能捕获RuntimeException异常和设置手动回滚TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()的问题)。

 1) 问题:看过网上介绍的很多事务代码段里,都是调用多个DAO方法操作数据表,但如果调用了其他Serviceimpl方法,事务是否能回滚?

  如果使用Mybaits持久化框架,简单来说DAO层就是映射mybatis中Mapperxml文件的接口,调用对应接口可以直接执行SQL语句,没有对入参做验证操作,而Serviceimpl方法封装了必要的验证过程,减少了外部调用DAO的重复验证工作量。

  情况一调用DAO方法:updat 表A、updat 表B是修改数据表的DAO方法,执行updat 表B时SQL报错异常时,则整个updateInfo方法回滚,之前执行成功的update表A也被撤回到原值。

  情况二调用Serviceimpl方法:若updat 表A是修改数据表的DAO方法,而updat 表B是Serviceimpl层方法,该方法内部调用了DAO方法。

 @Transactional
    public boolean add(HashMap<String, Object> map) {
        try {
            //update表A
            taDAO.update("1","小王");

            //update表B
            tbServImpl.update("22","技术部");

        } catch (Exception e) {
            logger.error(estr + e.toString());
            throw new RuntimeException(); //抛出RuntimeException异常给事务处理回滚 
        }
        return true;
    }

tbServImpl部分代码如下:

    public boolean update(String id,String name) {
        boolean flag=false;
        try {
            //update表B
            tbDAO.update(id,name);
            flag=true;
        } catch (Exception e) {
            logger.error(estr + e.toString());
            throw new RuntimeException(); //抛出RuntimeException异常给事务处理回滚 
        }
        return flag;
    }

此时,若tbServImpl.update执行SQL报错,updateInfo事务同样会回滚,说明一个事务代码段中,不一定限定只能执行DAO底层才能回滚,执行Serviceimpl层方法也同样适用。

2) 问题:什么样的异常会回滚?

上述代码中,SQL语句错误就会抛出异常被try catch捕获到,按正常网上的说法,事务只能捕获RuntimeException异常,所以这里的Exception e还不行,需要在catch中再抛出RuntimeException异常才能正常回滚。

3) 问题:如何手动回滚?

异常回滚是执行过程中抛出异常给事务去回滚,但有时执行没有异常报错,却执行失败需要手动回滚。比如update表B时传入的id有误,更新条数是0,此时需要手动回滚update表A的操作。手动回滚有两种方法可以实现

(1)判断执行结果有误时,手动new 一个异常抛出

 @Transactional
    public boolean add(HashMap<String, Object> map) {
        try {
            //update表A
            taDAO.update("1","小王");

            //update表B
            if(!tbServImpl.update("22","技术部")){
                //设置手动回滚 方法1
                throw new Exception();//手动抛异常给事务回滚

                //设置手动回滚 方法2
                //TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()
            }

        } catch (Exception e) {
            logger.error(estr + e.toString());
            throw new RuntimeException(); //抛出RuntimeException异常给事务处理回滚
        }
        return true;
    }

(2)设置手动回滚TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(),代码同上。

(3)回滚点

使用Object savePoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint(); 设置回滚点,

使用TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savePoint);回滚到savePoint。
 

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奋斗鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值