当前位置: 首页 > news >正文

兼职做诚信网站认证好123上网主页

兼职做诚信网站认证,好123上网主页,专业建设的基本要素,做垂直类网站介绍 本篇对Springboot事务控制中A方法调用B方法Transactional生效与不生效情况进行实战总结,让容易忘记或者困扰初学者甚至老鸟的开发者,只需要看这一篇文章即可立马找到解决方案,这就是干货的价值。喜欢的朋友别忘记来个一键三连哈&#x…

介绍

本篇对Springboot事务控制中A方法调用B方法@Transactional生效与不生效情况进行实战总结,让容易忘记或者困扰初学者甚至老鸟的开发者,只需要看这一篇文章即可立马找到解决方案,这就是干货的价值。喜欢的朋友别忘记来个一键三连哈:)

实战步骤

由于A方法调用B方法的情况较多,此处按照 一定的命名规则复现各种情况。
例如:

c代表class,c0代表不同类,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 LambdaQueryWrapper<UserEntity>().eq(UserEntity::getUsername,username));entity.setPassword("123456");userService.updateById(entity);}/*** 制造异常*/public void makeException() {int i=1/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/105687331
  • https://juejin.cn/post/7031446300142862373
  • 【@Transactional注解失效的几种情况】
    https://blog.csdn.net/Yaml4/article/details/138123693
http://www.shuangfujiaoyu.com/news/21254.html

相关文章:

  • 政府内网网站建设sem推广竞价
  • ui设计工具西安官网seo技术
  • 重庆广告牌制作武汉百度推广seo
  • 网站关键词库百度知道个人中心
  • 开网店在线咨询新网站seo外包
  • 游戏链接大全可复制seo成都培训
  • 优质服务的网站设计制作做网络营销推广
  • 广东网站建设推荐《新闻联播》 今天
  • 广告设计公司公司简介模板百中搜优化软件
  • 单产品网站建设宁波靠谱营销型网站建设
  • 青岛北京网站建设2023年度最火关键词
  • 两学一做网站条幅网址大全下载
  • 徐水住房建设局网站alexa排名查询统计
  • 太原高端网站建设搜索引擎优化叫什么
  • 武汉网站建设公司厂家地址厦门百度竞价推广
  • 17网站一起做网店深圳福州seo管理
  • 网站切片 做程序网上打广告有哪些软件
  • 基于jsp的精品课程网站建设网站建站设计
  • asp网站如何安装网站优化外包推荐
  • 图书馆管理网站建设logoseo方法培训
  • 做网站费用上海企业门户网站
  • 愿意合作做游戏的网站平台seo教学网seo
  • 网站做视频的软件有哪些搜狗引擎搜索
  • vr模式的网站建设公司输入搜索内容
  • 做网站的骗局营销托管全网营销推广
  • 网站建设贝尔利nba湖人队最新消息
  • 微网站独立域名上海好的网络推广公司
  • 视频网站主持人爱站网 关键词挖掘工具站长工具
  • 最便宜的外贸网站建设百度服务中心投诉
  • 网站用什么空间好长沙排名推广