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

34 篇文章 0 订阅
2 篇文章 0 订阅

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

这样的情景可能不常见,但是还是会有的,一旦遇到,如果业务比较复杂,就会很麻烦,但是还是有解决的方案的,比如将一个service方法拆成两个方法,也就是将两个操作的事务分开。但是这只适用与业务比较简单的,如果出现多次数据库的写操作,而我们调用的系统只需要其中一个写操作的最新数据,如果我们将它分开,那么如果调用目标系统出现异常的时候,那么之前的写操作就不能回滚了。

举个简单的例子:

@Service
public class ServiceA {

  @Transactional
  public void doSomething(){
    
    向数据库中添加数据;
    
    调用其他系统;
  }
}

这里就用伪代码来做示例了,当我们执行了“向数据库中添加数据”,我们去数据库中查询,发现并没有我们添加的数据,但是当我们的service这个方法执行完成之后,数据库中就有这条数据了,这是由于数据库的隔离性造成的。

Spring中的事务注解 @transactional 提供了一个参数:

Propagation propagation() default Propagation.REQUIRED;

这个参数是定义 Spring 事务的传递性的,默认值为:required,也就是如果有事务,就加入事务,如果没有,就创建事务。这个参数的值有很多,例如:REQUIRES_NEW,这个值就代表创建一个新的事务,与原来的事务分开。这个好像能解决我们的问题。

我们将刚刚那个方法修改一下:

@Service
public class ServiceA {

  @Transactional
  public void doSomething(){
    
    insert();
    
    调用其他系统;
  }
  
  @Transactional(propagation = Propagation.REQUIRES_NEW)
  public void insert(){
    向数据库中添加数据;
  }
}

执行之后,发现结果还是没有改变,必须要整体执行完成,数据库中数据才会出现,说明还是在一个事务中。Spring的核心思想,推荐你看看。

我们再将代码修改一下:

@Service
public class ServiceA {

  @Autowired
  private ServiceB serviceB;
  @Transactional
  public void doSomething(){
    
    serviceB.insert();
    
    调用其他系统;
  }
}
@Service
public class ServiceB {

  @Transactional(propagation = Propagation.REQUIRES_NEW)
  public void insert(){
    向数据库中添加数据;
  }
}

我们将要事务分离出来的方法写在另一个service中,再次测试,发现执行完插入语句之后,数据库中就已经能查到数据了,说明事务分离了,完成了我们的需求。
当然 Spring 其实也考虑这个,在 Spring 的配置中,我们只需要添加标签:

<aop:aspectj-autoproxy expose-proxy="true"/>

或者

<aop:config expose-proxy="true">

并且在代码的调用中要求使用代理对象去调用即可:

((ServiceA ) AopContext.currentProxy()).insert();

总结:用通俗话的来解释就是,自己抓自己头发抓不起来。借助别的东西能抓起来。直接调用,相当于调用原始方法,隔离级别传播属性会传递;如果注入调用,相当于调用代理对象,设置的传播属性才会生效。(即:原始方法代理方法的区别)

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring,我们可以通过声明式事务管理或编程式事务管理来开启事务。 1. 声明式事务管理:通过在XML配置文件定义事务切面,指定需要进行事务管理的方法或类。 示例代码: ``` <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="save*" propagation="REQUIRED" /> <tx:method name="update*" propagation="REQUIRED" /> <tx:method name="delete*" propagation="REQUIRED" /> <tx:method name="*" read-only="true" /> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="serviceMethods" expression="execution(* com.example.service..*.*(..))" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethods" /> </aop:config> ``` 2. 编程式事务管理:通过在代码使用TransactionTemplate或编程式事务通知来开启事务。 示例代码: ``` @Autowired private DataSourceTransactionManager transactionManager; public void save(User user) { TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager); transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) { userDao.save(user); } }); } ``` 以上是开启事务的两种方式,选择哪种方式取决于应用程序的需求和个人偏好。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值