大厂数据库事务实践-事务生效就能保证正确回滚?

作者 : 开心源码 本文共1455个字,预计阅读时间需要4分钟 发布时间: 2022-05-13 共264人阅读

AOP实现事务:使用try?c/atch包裹@Transactional注解的方法,当方法出现异常并满足肯定条件时,在catch里能设置事务回滚,没有异常则直接提交事务。

“肯定条件”包括:

  • 只有异常传播出了标记了@Transactional注解的方法,事务才能回滚。在Spring的TransactionAspectSupport里有个 invokeWithinTransaction方法,里面就是解决事务的逻辑。可以看到,只有捕获到异常才能进行后续事务解决:

    image

  • 默认情况下,出现RuntimeException(非受检异常)或者Error,Spring才会回滚事务。

打开Spring的DefaultTransactionAttribute

  • 受检异常一般是业务异常或者是相似另一种方法的返回值,出现这样的异常可能业务还能完成,所以不会主动回滚
  • 而Error或者RuntimeException代表非预期结果,应回滚

    image

反面教材

注册客户:

  • createUserError1会抛RuntimeException,但方法内的catch所有异常:

    image

  • createUserError2,注册客户同时会有一次otherTask文件读,若读文件失败,希望客户注册的DB操作回滚。这里虽无捕获异常,但因otherTask抛受检异常,createUserError2传播出去的也是受检异常,事务同样不回滚:
    image
  • readFile

    image

createUserError1、2这俩方法的实现和调用,尽管避开了事务不生效的坑,但因异常解决不当,文件操作出现异常时仍旧不回滚事务。

修复bug

以及如何通过日志来验证能否修复成功。针对这2种情况,对应的修复方法如下。

1 假如希望自己捕获异常并解决,可手动设置让当前事务处回滚态

@Transactionalpublic void createUserRight1(String name) {    try {        userRepository.save(new UserEntity(name));        throw new RuntimeException("error");    } catch (Exception ex) {        log.error("create user failed", ex);        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();    }}

查看日志,事务确定回滚。

Transactional code has requested rollback:手动请求回滚。

2 在注解中公告,期望遇到所有的Exception都回滚事务

以突破默认不回滚受检异常的限制。

image

查看日志,提醒回滚:
[图片上传失败…(image-cd575d-1605664603758)]

该案例有DB操作、IO操作,在IO操作问题时期望DB事务也回滚,以确保逻辑一致性。

小结

因为异常解决不正确,导致尽管事务生效,但出现异常时没回滚。
Spring默认只对被@Transactional注解的方法出现RuntimeExceptionError时回滚,所以若方法捕获了异常,就需要通过手写代码解决事务回滚。
若希望Spring针对其余异常也可回滚,可相应配置@Transactional注解的rollbackFornoRollbackFor属性覆盖Spring的默认配置。

有些业务可能包含屡次DB操作,不肯定希望将两次操作作为一个事务,这时就需仔细考虑事务传播的配置。

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 大厂数据库事务实践-事务生效就能保证正确回滚?

发表回复