当前位置:首页 > Java技术 > SpringBoot事务不起作用问题的解决方案

SpringBoot事务不起作用问题的解决方案

2022年11月06日 09:33:29Java技术10

背景

在做业务开发时,遇到了一个事务不起作用的问题。大概流程是这样的,方法内部的方法调用了一个带事务的方法,失败后事务没有回滚。查阅资料后,问题得到解决,记录下来分享给大家。

场景

在一个UserService里面,一个内部方法callSaveUser调用该service里面的saveUser方法 

  @Override
  @Transactional(rollbackFor = RuntimeException.class)
  public void saveUser(User user) {
    userMapper.save(user);
    throw new RuntimeException("");
  }
 
  /**
   * 内部调用保存用户方法
   *
   * @param user
   */
  @Override
  public void callSaveUser(User user) {
    this.saveUser(user);
  }

原因

AOP使用的是动态代理的机制,它会给类生成一个代理类,事务的相关操作都在代理类上完成。内部方式使用this调用方式时,使用的是实例调用,并没有通过代理类调用方法,所以会导致事务失效。

过程如下图:

SpringBoot事务不起作用问题的解决方案 _ JavaClub全栈架构师技术笔记
首先调用的是AOP代理对象而不是目标对象,首先执行事务切面,事务切面内部通过TransactionInterceptor环绕增强进行事务的增强,即进入目标方法之前开启事务,退出目标方法时提交/回滚事务。

解决办法

1. 通过初始化方法在目标对象中注入代理对象

注入自身bean

@Autowired
@Lazy
private UserService service;
修改方法调用

/**
   * 解决方法一 在bean中将自己注入进来
   * @param user
   */
  @Override
  public void callSaveUser(User user) {
    this.service.saveUser(user);
  }

总结:只能解决 普通(无循环依赖)的 的Bean注入AOP代理,无法解决循环依赖的AOP代理对象注入问题,即无法解决目标对象的自我调用问题。

2. 通过ApplicationContext引入bean

注入ApplicationContext

@Autowired
ApplicationContext applicationContext;
修改方法调用

/**
   * 解决方法二 通过applicationContext获取到bean
   * @param user
   */
  @Override
  public void callSaveUser(User user) {
    ((UserService)applicationContext.getBean("userService")).saveUser(user);
  }

总结:能解决普通(无循环依赖)的AOP代理对象注入问题,而且也能解决循环依赖(应该是singleton之间的循环依赖)造成的目标对象无法注入AOP代理对象问题,但该解决方案不适合解决循环依赖中包含prototype Bean的自我调用问题。

3. 通过AopContext获取当前类的代理类(推荐)

通过AopContext获取当前类的代理类,直接通过代理类调用方法在引导类上添加@EnableAspectJAutoProxy(exposeProxy=true)注解,然后修改callSaveUser方法

/**
   * 解决方法三 通过applicationContext获取到bean
   *
   * @param user
   */
  @Override
  public void invokeInsertUser(User user) {
    ((UserService) AopContext.currentProxy()).callSaveUser(user);
  }

原理:

  1. 在进入代理对象之后通过AopContext.serCurrentProxy(proxy)暴露当前代理对象ThreadLocal,并保存上次ThreadLocal绑定的代理对象为oldProxy;
  2. 接下来我们可以通过 AopContext.currentProxy() 获取当前代理对象;
  3. 在退出代理对象之前要重新将ThreadLocal绑定的代理对象设置为上一次的代理对象,即AopContext.serCurrentProxy(oldProxy)。

有些人不喜欢这种方式,说通过ThreadLocal暴露有性能问题,其实这个不需要考虑,因为事务相关的(Session和Connection)内部也是通过SessionHolder和ConnectionHolder暴露ThreadLocal实现的。

作者:菠萝-琪琪
来源链接:https://blog.csdn.net/wmq880204/article/details/118458270

版权声明:
1、JavaClub(https://www.javaclub.cn)以学习交流为目的,由作者投稿、网友推荐和小编整理收藏优秀的IT技术及相关内容,包括但不限于文字、图片、音频、视频、软件、程序等,其均来自互联网,本站不享有版权,版权归原作者所有。

2、本站提供的内容仅用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯相关权利人及本网站的合法权利。
3、本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站(javaclubcn@163.com),我们将第一时间核实后及时予以删除。


本文链接:https://www.javaclub.cn/java/68109.html

分享给朋友:

“SpringBoot事务不起作用问题的解决方案” 的相关文章

SpringBoot多数据源配置事务

在多数据源中配置事务,其实对于SpringBoot来很简单,当然这个的前提是首先把多数据源都配好的情况下,如果不会多数据源配置,请看该系列 SpringBoot整合多数据源 首先在启动类配置 @SpringBootApplication @E...

Springboot事务配置

在一个config类名上面加入注解,用来开启事务 @EnableTransactionManagement 再加入一个BEAN类来配置事务 @Bean public DataSourceTransactionManager transactionMa...

springBoot service 事务注解@Transactional不起作用的解决

在springBoot使用事物时,发现事务并没有正常执行,没有进行回滚 @Transactional public void add(String companyName,String name) throws MyException{ compan...

springboot+mongodb @Transactional事务注解失效问题处理

问题场景 在一个@service方法上加上 @Transactional(rollbackFor = Exception.class)注解后,发现该方法中调用的另一个方法中抛出异常,在调用该方法之前的对表的修改未回滚,生效了。 问题代码:...

SpringBoot事务不生效可能存在的原因

1.mysql表必须支持事务:引擎为INNODB 2.SpringBoot启动事务@EnableTransactionManagement 3.方法上加注解@Transactional//默认只对RuntimeException起作用,可修改 4.方法必须为pu...

springboot 事务嵌套问题

关于事物的基本概念等这里就不介绍了。 Spring声明式事物的实现,有两种方式;第一种是配置xml,第二种是使用相关注解(这两种方式可详见《程序员成长笔记(一)》的相关章节)。SpringBoot中默认配置了第二种方式,所以,SpringBoot直接使用注解即可...

Spring Boot(十二)Spring Boot中数据库事务的使用

Spring Boot(十二)Spring Boot中数据库事务的使用

你好,【程序职场】专注于:Spring Boot ,微服务 和 前端APP开发,闲暇之余一起聊聊职场规划,个人成长,还能带你一起探索 副业赚钱渠道,在提升技术的同时我们一起交流 敏捷流程 提高工作效率,从技术到管理一步步提升自我!   标签:一个执着的职场程序...

事务的隔离级别及springboot使用事务

事务会产生的问题:脏读、不可重复读、幻读。 事务的隔离级别有:读未提交、读已提交、重复读、串行化。 读未提交是指,一个事务还没提交时,它做的变更就能被别的事务看到。 读已提交是指,一个事务提交之后,它做的变更才会被其他事务看到。...

springboot事务不生效的情况

Spring Boot 使用事务:首先使用注解 @EnableTransactionManagement 开启事务支持,然后在Service方法上添加注解 @Transactional 便可。在Service中,被 @Transactional 注解的方...

Springboot中声明事务@Transactional,方法被try catch不做任何处理真的不会回滚吗?

 今天代码评审,碰到了@Transactional 事务的分歧,我认为,只要方法被try catch了,并且没有做任何处理,就不会回滚事务,但事实并不是这样,因此我还跟同事打赌输了一支雪糕!!!  特此来csdn发个贴,这也是我都第一次发帖,哈哈~~~...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。