推荐学习肝了十天半月 , 献上纯手绘“Spring/Cloud/Boot/MVC”全家桶脑图微服务架构秘籍:SpringCloud+SpringCloudAlibaba , 全网疯传
注解@Transactional配置的方法非public权限修饰;注解@Transactional所在类非Spring容器管理的bean;注解@Transactional所在类中 , 注解修饰的方法被类内部方法调用;业务代码抛出异常类型非RuntimeException , 事务失效;业务代码中存在异常时 , 使用try…catch…语句块捕获 , 而catch语句块没有thrownewRuntimeExecption异常;(最难被排查到问题且容易忽略)注解@Transactional中Propagation属性值设置错误即Propagation.NOT_SUPPORTED(一般不会设置此种传播机制)mysql关系型数据库 , 且存储引擎是MyISAM而非InnoDB , 则事务会不起作用(基本开发中不会遇到);下面基于以上场景 , 溪源给小伙伴们详细解释;非public权限修饰参考Spring官方文档介绍 , 摘要、译文如下:Whenusingproxies,youshouldapplythe@Transactionalannotationonlytomethodswithpublicvisibility.Ifyoudoannotateprotected,privateorpackage-visiblemethodswiththe@Transactionalannotation,noerrorisraised,buttheannotatedmethoddoesnotexhibittheconfiguredtransactionalsettings.ConsidertheuseofAspectJ(seebelow)ifyouneedtoannotatenon-publicmethods.译文使用代理时 , 您应该只将@Transactional注释应用于具有公共可见性的方法 。 如果使用@Transactional注释对受保护的、私有的或包可见的方法进行注释 , 则不会引发错误 , 但带注释的方法不会显示配置的事务设置 。 如果需要注释非公共方法 , 请考虑使用AspectJ(见下文) 。简言之:@Transactional只能用于public的方法上 , 否则事务不会失效 , 如果要用在非public方法上 , 可以开启AspectJ代理模式 。
目前 , 如果@Transactional注解作用在非public方法上 , 编译器也会给与明显的提示 , 如图:
java.lang.RuntimeExceptionatcom.qxy.common.service.impl.ClassServiceImpl.insertClassByException(ClassServiceImpl.java:34)atcom.qxy.common.service.impl.ClassServiceImpl.insertClass(ClassServiceImpl.java:27)atcom.qxy.common.service.impl.ClassServiceImpl$$FastClassBySpringCGLIB$$a1c03d8.invoke()虽然业务代码报错了 , 但是数据库中已经成功插入数据 , 事务并未生效;
publicvoidinsertClass(ClassDoclassDo)throwsCustomException{//insertClassByException(classDo);((ClassServiceImpl)AopContext.currentProxy()).insertClassByException(classDo);}测试用例:@TestpublicvoidinsertInnerExceptionTest()throwsCustomException{classDo.setClassId(3);classDo.setClassName("java_3");classDo.setClassNo("java_3");classService.insertClass(classDo);}业务代码抛出异常 , 数据库未插入新数据 , 达到我们的目的 , 成功解决一个事务失效问题;
java.lang.IllegalStateException:Cannotfindcurrentproxy:Set'exposeProxy'propertyonAdvisedto'true'tomakeitavailable.atorg.springframework.aop.framework.AopContext.currentProxy(AopContext.java:69)atcom.qxy.common.service.impl.ClassServiceImpl.insertClass(ClassServiceImpl.java:28)异常类型非RuntimeException这种事务失效场景也是非常难排查问题的 , 如果没有深究源码实现 , 估计要花费一番功夫啦;@ServicepublicclassClassServiceImplimplementsClassService{@AutowiredprivateClassMapperclassMapper;//@Override//@Transactional(propagation=Propagation.NESTED,rollbackFor=Exception.class)publicvoidinsertClass(ClassDoclassDo)throwsException{//即使此处使用代理对象调用内部事务方法 , 数据依然未发生回滚 , 事务机制亦然失效((ClassServiceImpl)AopContext.currentProxy()).insertClassByException(classDo);}@Override@Transactional(propagation=Propagation.REQUIRED)publicvoidinsertClassByException(ClassDoclassDo)throwsException{classMapper.insertClass(classDo);//抛出非RuntimeException类型thrownewException();}测试用例:@TestpublicvoidinsertInnerExceptionTest()throwsException{classDo.setClassId(3);classDo.setClassName("java_3");classDo.setClassNo("java_3");classService.insertClass(classDo);}}运行结果:业务代码抛出异常 , 但是数据库发生更新操作;
java.lang.Exceptionatcom.qxy.common.service.impl.ClassServiceImpl.insertClassByException(ClassServiceImpl.java:35)atcom.qxy.common.service.impl.ClassServiceImpl$$FastClassBySpringCGLIB$$a1c03d8.invoke()atorg.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)数据库依然插入数据 , 不是我们想要的结果啊 , 赶紧修改吧 , 产品经理来追啦~
@Override@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)publicvoidinsertClassByException(ClassDoclassDo)throwsException{classMapper.insertClass(classDo);thrownewException();}捕获异常后 , 却未抛出异常在事务方法中使用try-catch , 导致异常无法抛出 , 自然会导致事务失效 。 @ServicepublicclassClassServiceImplimplementsClassService{@AutowiredprivateClassMapperclassMapper;//@OverridepublicvoidinsertClass(ClassDoclassDo){((ClassServiceImpl)AopContext.currentProxy()).insertClassByException(classDo);}@Override@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)publicvoidinsertClassByException(ClassDoclassDo){classMapper.insertClass(classDo);try{inti=1/0;}catch(Exceptione){e.printStackTrace();}}}测试用例:@TestpublicvoidinsertInnerExceptionTest(){classDo.setClassId(4);classDo.setClassName("java_4");classDo.setClassNo("java_4");classService.insertClass(classDo);}执行结果:
@Override@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)publicvoidinsertClassByException(ClassDoclassDo){classMapper.insertClass(classDo);try{inti=1/0;}catch(Exceptione){e.printStackTrace();thrownewRuntimeException();}}事务传播行为设置异常此种事务传播行为不是特殊自定义设置 , 基本上不会使用Propagation.NOT_SUPPORTED , 不支持事务@Transactional(propagation=Propagation.NOT_SUPPORTED,rollbackFor=Exception.class)publicvoidinsertClassByException(ClassDoclassDo){classMapper.insertClass(classDo);try{inti=1/0;}catch(Exceptione){e.printStackTrace();thrownewRuntimeException();}}数据库存储引擎不支持事务以MySQL关系型数据为例 , 如果其存储引擎设置为MyISAM , 则事务失效 , 因为MyISMA引擎是不支持事务操作的;故若要事务生效 , 则需要设置存储引擎为InnoDB;目前MySQL从5.5.5版本开始默认存储引擎是:InnoDB;作者:溪~源
原文链接:
推荐阅读
-
香港新冠肺炎确诊病例逼近4000例,粤澳收紧港人入境措施
-
糯米养胃又御寒,但这两种人却一口也不能多吃 糯米的功效与作用及禁忌
-
『三角形ufo』美承认UFO视频为真实后,无巧不成书,捷克闪电中现疑似三角形UFO
-
长安逸动:暗访了几位长安逸动plus的车主,他们详细说了优缺点,你咋看呢?
-
#阿兴谈野史#巨款买回一堆“垃圾”,结果却成为神器,李鸿章访问德国被骗
-
中金网|GDP创纪录增幅是特朗普的及时雨吗?黄金困于风险情绪改善
-
-
体坛焦点|世体:贝蒂斯有意下赛季租借皇马小将迪亚斯
-
-
-
八卦请等等我请尽快远离,往后会变得越来越好!,身边有3种特征的朋友
-
-
「对你宣说」李小璐直播光打赏收入近百万,有谁注意到一位送礼物的粉丝网名
-
极客手机侠2000元能买到的最好5g手机,这几款都很火
-
-
特朗普|243票赞成164票反对,美众议院通过一重要决议,特朗普成“靶子”
-
-
-
音频怪物继索尼之后,2020年又一款会卖爆蓝牙耳机,外观让人心动
-
「第五大道」时尚穿搭清爽随性又减龄,每一套都美到爆炸,阚清子气质独特