当前位置: 首页 > 编程笔记 >

Spring如何在一个事务中开启另一个事务

冷俊健
2023-03-14
本文向大家介绍Spring如何在一个事务中开启另一个事务,包括了Spring如何在一个事务中开启另一个事务的使用技巧和注意事项,需要的朋友参考一下

这篇文章主要介绍了Spring如何在一个事务中开启另一个事务,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

spring使用@Transactional开启事务,而且该注解使用propagation属性来指定事务的传播级别

@Transactional(propagation =Propagation.REQUIRES_NEW) // 开启一个新事务

使用REQUIRES_NEW就会开启一个新的事务吗? 答案并不是.

请看下面的这个示例

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import qinfeng.zheng.learnpagequery.domain.UserDO;
import qinfeng.zheng.learnpagequery.mapper.UserMapper;

@Service
public class UserService {
  @Autowired
  private UserMapper userMapper;


  @Transactional(rollbackFor = Exception.class)
  public void doSomething(UserDO userDo) {
    insert(userDo);
    doOther();
  }

  @Transactional(propagation =Propagation.REQUIRES_NEW) // 开启一个新事务
  public void insert(UserDO userDo) {
    userMapper.insert(userDo);
  }

  public void doOther() {
    System.out.println("做一些其它的事,比如调用其它的系统");
  }
}

在调用doSomething方法时,开启了一个事务,该方法中包括insert和doOther, 但是insert方法上也开启了一个事务. 按道理应该有两个事务控制,可事实上并不是, insert方法的事务无效. 这就跟spring事务原理有关系, spring框架是通过TransactionInterceptor类来控制事务开启,提交,回滚等, 它会创建一个目标类的代理类. 而在本示例中,doSomething方法调用insert方法时,并不是通过代理类去调用,而是通过this调用本身的方法insert方法.所以insert方法的事务并不会开启.

解决方法

1. 将insert方法抽取到另一个XxxService方法中, 然后再将这个XxxService注入到UserService类中,通过xxxService.insert()调用, 这样insert方法的事务就会生效了.

2. 第2种方式通过AopContext创建一个代理

 在项目启动类上开启 exposeProxy = true

@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
@Transactional(rollbackFor = Exception.class)
public void doSomething(UserDO userDo) {
  UserService userService = (UserService) AopContext.currentProxy();
  userService.insert(userDo); // 这样insert方法事务生效
  doOther();
}

备注: 在springboot1.x中使用@EnableTransactionManagement开启事务, 但是在springboot2.x中,默认就开启了事务,所以勿须在启动类上添加此注解

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。

 类似资料:
  • 问题内容: 也许,我做错了,但在以下情况下我找不到好的出路。 我想对使用下面的Spring Batch执行作业的服务进行单元测试。通过在单独的线程中预配置来执行作业。在我的单元测试中,我想: 创建几个域对象并通过DAO持久化它们 调用服务方法启动工作 等待作业完成 使用DAO检索域对象并检查其状态 显然,以上所有操作都应在一个事务中执行,但是不幸的是,事务不会传播到新线程中(我理解这背后的原理)。

  • 我正在尝试使用Hibernate保存数据。一切都发生在同一会话中。逻辑如下: 1)开始交易并尝试保存: 2) 如果新记录违反完整性约束,请在外包装方法中捕获异常,打开另一个事务并查询更多数据 问题是当第二个事务执行时query.list它会抛出一个应该与前一个事务链接的异常。 SQLIntegrityConstraintViolationException:ORA-00001:唯一约束 我应该从另

  • 问题内容: 为了了解Spring事务的工作原理,我想知道在以下情况下发生的情况:如果一种方法标记为,而另一种方法标记为。 假设配置使用所有默认设置。 现在,如果我要输入,显然可以开始交易。然后,钻进去会发生什么?交易已经存在的事实会导致没有新的交易诞生,还是我在这里创建两个交易? 关于Propagation的文档(在下面引用)似乎涵盖了这一点,但是我想验证一下我的理解 Propagation:通常

  • 我有一个方法,我试图改变一些实体,在这个方法中我也想保存交易信息。当发生任何异常时,我想回滚保存实体,但仍然想保存交易。那么如何为实体事务建立一个存储库,而不是为事务建立一个存储库呢? 有存储库的代码 但这没有帮助。保存放置在最后一个块中的交易。 使现代化 我用AOP解决了这个问题。我在aspect advice中创建了事务对象,并将其保存在JPA事务之外。

  • 如何实现一个事务读取的行不允许另一个事务读取的情况? 从我的一个包含列A-F的表中,我需要选择。使用max值并根据一些计算,我将不得不执行其他插入语句。 在可序列化隔离级别下,2个事务读取相同的最大值。这将导致一个事务的锁等待和另一个事务上的死锁。

  • 是否可以对同一个事务多次调用< code > dslcontext . transaction result()? 我希望在同一个事务中向不同的表中插入行,并将主键返回给封闭(非事务)代码块。 我知道我可以创建一些自定义的返回类型来保存多个值,但是从代码可读性的角度来看,最好是多次调用< code > dslcontext . transaction result()并每次传递一个单独的结果。