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

Spring事务的失效场景

事务失效场景

  1. 方法用private或final修饰
    Spring底层使用了AOP,而AOP的实现方式有两种,分别是JDK动态代理和CGLIB,JDK动态代理是实现抽象接口,CGLIB是继承父类,无论哪种方式,都需要重写方法来进行方法增强,而用private或final修饰的方法都是不能被重写的

  2. 方法自调用(如何解决方法自调用导致的事务失效)
    UserService类中开启A方法调用B方法,直接调用A方法会导致B方法的Transactional注解不生效,从而导致事务失效

@Component
public class UserService{@Autowiredprivate JdbcTemplate jdbcTemplate;@Transactionalpublic void A() {//this.B()和B()同理B();}@Transactional(propagation = Propagation.NEVER)public void B(){jdbcTemplate.execute("insert into user values(1, 1, '1')");throw new NullPointerException();}
}

为什么事务会失效?Spring生成的代理类大致如下,调用A方法会执行$Proxy0.A(),而B方法是被代理对象target调用的,所以方法不会被增强

public class $Proxy0 extends UserService {private UserService target;public void A() {//建立数据库连接ConnectionConnection connection = DriverManager.getConnection("jdbc:mysql:///user");connection.setAutoCommit(false);try{target.A();}catch(RuntimeException exception){connection.rollback();return;}connection.commit();}
}
  1. 多线程调用
    执行SQL时会从ThreadLocal里获取数据库连接对象,而ThreadLocal是线程隔离的,新线程无法从主线程的ThreadLocal里获取数据库连接对象,所以只能新建一个数据库连接来执行SQL,此时autoCommit默认是true,执行完SQL就会自动提交,抛出异常也就不能回滚了
@Component
public class UserService {@Autowiredprivate JdbcTemplate jdbcTemplate;@Transactionalpublic void B() {new Thread(() -> {jdbcTemplate.execute("insert into user values(1, 1, '1')");throw new NullPointerException();}).start();}
}
  1. 类没有被Spring管理

  2. 数据库不支持事务

  3. 异常被手动try-catch掉了

如何解决方法自调用导致的事务失效

  • 自己注入自己
@Component
public class UserService {@Autowiredprivate JdbcTemplate jdbcTemplate;@Autowiredprivate UserService userService;public void A() {//从Spring容器中取出代理对象userService.B();}@Transactionalpublic void B() {jdbcTemplate.execute("insert into user values(1, 1, '1')");throw new NullPointerException();}
}
  • 把被调用的方法拆分到别的Bean中,然后再把这个Bean注入进来
  • AopContext.currentProxy() + @EnableAspectJAutoProxy(exposeProxy = true)
@Component
public class UserService {@Autowiredprivate JdbcTemplate jdbcTemplate;public void A() {UserService userService = (UserService) AopContext.currentProxy();userService.B();}@Transactionalpublic void B() {jdbcTemplate.execute("insert into user values(1, 1, '1')");throw new NullPointerException();}
}
http://www.lryc.cn/news/6744.html

相关文章:

  • 芯动联科在科创板IPO过会:拟募资10亿元,金晓冬为实际控制人
  • 数据结构之单链表
  • 儿子跟妈妈关系不好怎么办?这里有解决办法!
  • 论文投稿指南——中文核心期刊推荐(植物保护)
  • 华科万维C++章节练习4_6
  • 详解子网技术
  • chatGTP的全称Chat Generative Pre-trained Transformer
  • hive数据存储格式
  • mysql数据库备份与恢复
  • 《NFL橄榄球》:辛辛那提猛虎·橄榄1号位
  • 2、线程、块和网格
  • C++ 算法主题系列之贪心算法的贪心之术
  • 请注意,PDF正在传播恶意软件
  • 【Kubernetes】【二】环境搭建 环境初始化
  • Python:每日一题之发现环(DFS)
  • C++设计模式(14)——享元模式
  • SpringCloud之Eureka客户端服务启动报Cannot execute request on any known server解决
  • 从零开始搭建kubernetes集群环境(虚拟机/kubeadm方式)
  • 【零基础入门前端系列】—表格(五)
  • C#开发的OpenRA的只读字典IReadOnlyDictionary实现
  • mulesoft MCIA 破釜沉舟备考 2023.02.14.06
  • Python网络爬虫 学习笔记(1)requests库爬虫
  • Splay
  • 智能网联汽车ASIL安全等级如何划分
  • Stable Diffusion 1 - 初始跑通 文字生成图片
  • 【cuda入门系列】通过代码真实打印线程ID
  • 【Python语言基础】——Python NumPy 数据类型
  • 数据工程师需要具备哪些技能?
  • Cosmos 基础 -- Ignite CLI(二)Module basics: Blog
  • Quartz 快速入门案例,看这一篇就够了