博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
99%的Java程序员都不知道的Spring中的@Transactional注解的坑
阅读量:6267 次
发布时间:2019-06-22

本文共 2333 字,大约阅读时间需要 7 分钟。

  在我们开发中很多时候都要用到事务,例如转账、充值等等的操作,这些我就不多BB了,于是很多人就选择最简单的方式@Transactional注解,但是你真的测试过事务异常的时候会回滚吗?等生产环境遇到了在来查找原因那就晚了,下面就说一下该注解的一下坑吧。

Transactional常见的几种失效原因

  • 没有配置事务管理器。配置方式如下:

  • 同一个类中,?一个未标注@Transactional的方法去调用标有@Transactional的方法,?事务会失效。

  • 该注解只能应用到?public?可见度的方法上。?如果应用在protected、private或者?package可见度的方法上,也不会报错,但是事务设置不会起作用。

  • 数据库引擎本身不支持事务,比如说MySQL数据库中的myisam,事务是不起作用的。

  • Spring只会对unchecked异常进行事务回滚;如果是checked异常则不回滚。

  那什么是checked异常,什么是unchecked异常?我们把派生于Error或者RuntimeException的异常称为unchecked异常,所有其他的异常成为checked异常。什么又是RuntimeException呢,用《Effective Java》上的一句话来说吧。

  Use checked exceptions for recoverable conditions and runtime exceptions for programming errors (Item 58 in 2nd edition)

  从这句话中我们可以简单引申一下,也就是说,如果出现了RuntimeException,就一定是程序员自身的问题。比如说,数组下标越界和访问空指针异常等等,只要你稍加留心这些异常都是在编码阶段可以避免的异常。

  针对最后一种情况,我们简单模拟一下吧,前期的准备工作这里就跳过了,直接开始我们今天的测试。测试之前数据库中的emp表只有一条数据信息。

unchecked异常事务回滚验证

  现在我们先模拟正常情况(RuntimeException, 我们使用最简单的数组越界异常。)   废话不多说,直接上代码:

@Test    @Transactional    public void test(){        Emp emp1 = new Emp();        emp1.setEmpname("测试二");        emp1.setEmail("test02@qq.com");        empService.insertEmp(emp1);        /**         * 模拟RuntimeException异常回滚         * */        int[]  arr = {0};        System.out.println(arr[1]);//越界        Emp emp2 = new Emp();        emp2.setEmpname("测试三");        emp2.setEmail("test03@qq.com");        empService.insertEmp(emp1);    }复制代码

  运行之后效果截图:

  程序运行之后,我们看下数据库的数据情况:
  代码运行之后,由于有RuntimeException异常抛出,所以事务回滚了,这两条数据都没保存成功。

checked异常事务回滚验证

  接下来模拟checked异常事务是否回滚问题,我们强制抛出一个FileNotFoundException异常。 ??   同样的,这里粘贴一下测试用的代码:

@Test    @Transactional    public void test() throws Exception{        Emp emp1 = new Emp();        emp1.setEmpname("测试四");        emp1.setEmail("test04@qq.com");        empService.insertEmp(emp1);                /**         * 文件一定不存在         * */        FileInputStream file = new FileInputStream("C:\\Users\\pokemon\\Documents\\abc.txt");                Emp emp2 = new Emp();        emp2.setEmpname("测试五");        emp2.setEmail("test05@qq.com");        empService.insertEmp(emp1);    }复制代码

  报错情况:

  程序运行之后,我们看下数据库的数据情况:

  从上面的截图可以看出,事务并没有回滚,empname是“测试四”的这条数据被写入数据库了。

  等等,这种情况我们无法预料,那应该怎么办?总不能坐以待毙吧。

解决方案

  这样添加事务@Transactional(rollbackOn = Exception.class), 不管检查异常还是非检查异常都会回滚。以上就是关于@Transactional注解事务的坑以及解决方案,如果感觉对你有用,算我没白忙活。

??欢迎大家关注我的微信公众号"Java架构师养成记",不定期分享各类面试题、爬坑记录。

转载地址:http://vzjpa.baihongyu.com/

你可能感兴趣的文章
Codeforces Round #271 (Div. 2) D. Flowers (递推 预处理)
查看>>
jacky自问自答-java并发编程
查看>>
Struts2+JSON数据
查看>>
zTree实现单独选中根节点中第一个节点
查看>>
Cocos2D-x设计模式发掘之中的一个:单例模式
查看>>
很强大的HTML+CSS+JS面试题(附带答案)
查看>>
用树莓派实现RGB LED的颜色控制——C语言版本号
查看>>
VC2012编译CEF3-转
查看>>
java 自己定义异常,记录日志简单说明!留着以后真接复制
查看>>
Android 使用AIDL实现进程间的通信
查看>>
机器学习(Machine Learning)&深度学习(Deep Learning)资料
查看>>
jquery的图片轮播 模板类型
查看>>
C# 获取文件名及扩展名
查看>>
Web安全学习计划
查看>>
输出有序数组的连续序列范围
查看>>
zinnia项目功能分析
查看>>
windows cmd for paramiko
查看>>
SQL经典面试题集锦
查看>>
View学习(一)-DecorView,measureSpec与LayoutParams
查看>>
色彩力量!21款你应该知道的优秀品牌设计
查看>>