网站上怎么做福彩卖家,ps制作个人网站首页,电子商务网站建设主管的策划案,小程序如何注册步骤介绍
本篇对Springboot事务控制中A方法调用B方法Transactional生效与不生效情况进行实战总结#xff0c;让容易忘记或者困扰初学者甚至老鸟的开发者#xff0c;只需要看这一篇文章即可立马找到解决方案#xff0c;这就是干货的价值。喜欢的朋友别忘记来个一键三连哈#x…介绍
本篇对Springboot事务控制中A方法调用B方法Transactional生效与不生效情况进行实战总结让容易忘记或者困扰初学者甚至老鸟的开发者只需要看这一篇文章即可立马找到解决方案这就是干货的价值。喜欢的朋友别忘记来个一键三连哈
实战步骤
由于A方法调用B方法的情况较多此处按照 一定的命名规则复现各种情况。 例如
c代表classc0代表不同类c1代表同类 a代表a方法a0代表a方法无事务注解a1代表有 b代表b方法b0代表b方法无事务注解b1代表有 e代表抛异常ea代表a方法中抛异常eb代表b方法执行抛异常
组合起来c1a0b1ea 表示同类中a调用b,b上有事务a中抛异常
创建表
CREATE TABLE tb_user (id int(11) NOT NULL AUTO_INCREMENT,username varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,password varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,nickname varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,PRIMARY KEY (id) USING BTREE
) ENGINE InnoDB AUTO_INCREMENT 36 CHARACTER SET utf8mb4 COLLATE utf8mb4_bin ROW_FORMAT Dynamic;创建测试类
AbstractUserService执行事务操作
Service
public class AbstractUserService {Autowiredprivate UserService userService;/*** 新增用户* param username*/public void saveUser(String username) {UserEntity userEntity new UserEntity();userEntity.setUsername(username);userService.save(userEntity);}/*** 更新密码* param username*/public void updatePassword(String username) {UserEntity entity userService.getOne(new LambdaQueryWrapperUserEntity().eq(UserEntity::getUsername,username));entity.setPassword(123456);userService.updateById(entity);}/*** 制造异常*/public void makeException() {int i1/0;}
}Service01 代表a类
Service
public class Service01 extends AbstractUserService{Autowiredprivate Service02 service02;// 同类调用public void c1_a0_b1_ea(String username){saveUser(username);this.b1(username,false);makeException();}public void c1_a0_b1_eb(String username){saveUser(username);this.b1(username,true);}Transactional(rollbackFor Exception.class)public void c1_a1_b0_ea(String username){saveUser(username);this.b0(username,false);makeException();}Transactional(rollbackFor Exception.class)public void c1_a1_b0_eb(String username){saveUser(username);this.b0(username,true);}Transactional(rollbackFor Exception.class)public void c1_a1_b1_ea(String username){saveUser(username);this.b1(username,false);makeException();}Transactional(rollbackFor Exception.class)public void c1_a1_b1_eb(String username){try{saveUser(username);this.b1(username,true);}catch (Exception e){System.out.println(c1_a1_b1_eb执行失败);throw new RuntimeException(c1_a1_b1_eb执行失败);}}// 不同类调用public void c0_a0_b1_ea(String username){saveUser(username);service02.b1(username,false);makeException();}public void c0_a0_b1_eb(String username){saveUser(username);service02.b1(username,true);}Transactional(rollbackFor Exception.class)public void c0_a1_b0_ea(String username){saveUser(username);service02.b0(username,false);makeException();}Transactional(rollbackFor Exception.class)public void c0_a1_b0_eb(String username){saveUser(username);service02.b0(username,true);}Transactional(rollbackFor Exception.class)public void c0_a1_b1_ea(String username){saveUser(username);service02.b1(username,false);makeException();}Transactional(rollbackFor Exception.class)public void c0_a1_b1_eb(String username){saveUser(username);service02.b1(username,true);}public void b0(String username,boolean hasException){updatePassword(username);if(hasException){makeException();}}Transactional(rollbackFor Exception.class)public void b1(String username, boolean hasException){updatePassword(username);if(hasException){makeException();}}}
Service02 代表b类
Service
public class Service02 extends AbstractUserService{public void b0(String username,boolean hasException){updatePassword(username);if(hasException){makeException();}}Transactional(rollbackFor Exception.class)public void b1(String username, boolean hasException){updatePassword(username);if(hasException){makeException();}}
}测试接口TestController
RestController
RequestMapping()
public class TestController {Autowiredprivate Service01 service01;/*** 同类* a没有事务b有 异常发生在a中 不会回滚* return*/GetMapping(/c1_a0_b1_ea)public String test1() {service01.c1_a0_b1_ea(c1_a0_b1_ea);return ok;}/*** 同类* a没有事务b有 异常发生在b中 不会回滚* return*/GetMapping(/c1_a0_b1_eb)public String test2() {service01.c1_a0_b1_eb(c1_a0_b1_eb);return ok;}/*** 同类* a有事务b没有 异常发生在a中 会回滚* return*/GetMapping(/c1_a1_b0_ea)public String test3() {service01.c1_a1_b0_ea(c1_a1_b0_ea);return ok;}/*** 同类* a有事务b没有 异常发生在b中 会回滚* return*/GetMapping(/c1_a1_b0_eb)public String test4() {service01.c1_a1_b0_eb(c1_a1_b0_eb);return ok;}/*** 同类* a有事务b有 异常发生在a中 会回滚* return*/GetMapping(/c1_a1_b1_ea)public String test5() {service01.c1_a1_b1_ea(c1_a1_b1_ea);return ok;}/*** 同类* a有事务b有 异常发生在b中 会回滚* return*/GetMapping(/c1_a1_b1_eb)public String test6() {service01.c1_a1_b1_eb(c1_a1_b1_eb);return ok;}/*** 不同类* a没有事务b有 异常发生在a中 不会回滚* return*/GetMapping(/c0_a0_b1_ea)public String test7() {service01.c0_a0_b1_ea(c0_a0_b1_ea);return ok;}/*** 不同类* a没有事务b有 异常发生在b中 只有b回滚* return*/GetMapping(/c0_a0_b1_eb)public String test8() {service01.c0_a0_b1_eb(c0_a0_b1_eb);return ok;}/*** 不同类* a有事务b没有 异常发生在a中 会回滚* return*/GetMapping(/c0_a1_b0_ea)public String test9() {service01.c0_a1_b0_ea(c0_a1_b0_ea);return ok;}/*** 不同类* a有事务b没有 异常发生在b中 会回滚* return*/GetMapping(/c0_a1_b0_eb)public String test10() {service01.c0_a1_b0_eb(c0_a1_b0_eb);return ok;}/*** 不同类* a有事务b有 异常发生在a中 会回滚* return*/GetMapping(/c0_a1_b1_ea)public String test11() {service01.c0_a1_b1_ea(c0_a1_b1_ea);return ok;}/*** 不同类* a有事务b有 异常发生在b中 会回滚* return*/GetMapping(/c0_a1_b1_eb)public String test12() {service01.c0_a1_b1_eb(c0_a1_b1_eb);return ok;}
}测试结果
http://localhost:9000/test/c0_a1_b1_eb
在浏览器中依次访问测试接口中的每个方法得到表中结果 以下情况未回滚或者半回滚不在表里的均正常回滚事务。
原理总结
原理 spring 在扫描bean的时候会扫描方法上是否包含Transactional注解如果包含spring会为这个bean动态地生成一个子类即代理类proxy代理类是继承原来那个bean的。 此时当这个有注解的方法被调用的时候实际上是由代理类来调用的代理类在调用之前就会启动transaction。然而如果这个有注解的方法是被同一个类中的其他方法调用的那么该方法的调用并没有通过代理类而是直接通过原来的那个bean所以就不会启动transaction我们看到的现象就是Transactional注解无效。
那回到一开始的问题我们调用的方法A不带注解因此代理类不开事务而是直接调用目标对象的方法。当进入目标对象的方法后执行的上下文已经变成目标对象本身了因为目标对象的代码是我们自己写的和事务没有半毛钱关系此时你再调用带注解的方法照样没有事务只是一个普通的方法调用而已。 简单来说内部调用本类方法不会再走代理了所以B的事务不起作用。
如果AB不同类A调用的事代理类B故B有事务。
参考文章
https://blog.csdn.net/weixin_36586564/article/details/105687331https://juejin.cn/post/7031446300142862373【Transactional注解失效的几种情况】 https://blog.csdn.net/Yaml4/article/details/138123693