在TransactionDefinition接口中定义了七个事务传播行为。
先说最常用的三个
PROPAGATION_REQUIRED 如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。
如果上下文中已经存在事务,那么就加入到事务中执行,如果当前上下文中不存在事务,则新建事务执行。所以这个级别通常能满足处理大多数的业务场景。
PROPAGATION_REQUIRES_NEW 总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
如果不起作用,可能的原因如下:调用方与被调用方写在了同一个service类里面,需要用Spring的上下文获取对象。
例如:((ABCServiceImpl) SpringContextHolder.getBean("注册的标识符"))
PROPAGATION_NESTED 如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行。
其他四个
PROPAGATION_SUPPORTS 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行。但是对于事务同步的事务管理器,PROPAGATION_SUPPORTS与不使用事务有少许不同。
如果上下文存在事务,则支持事务加入事务,如果没有事务,则使用非事务的方式执行
PROPAGATION_MANDATORY 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。
PROPAGATION_NOT_SUPPORTED 总是非事务地执行,并挂起任何存在的事务。
PROPAGATION_NEVER 总是非事务地执行,如果存在一个活动事务,则抛出异常
通常我们只会用到@Transactional(propagation = Propagation.REQUIRED)。
在特殊需求的时候需要在一个方法内部提前提交一部分事务或者是让内部的一段代码处于单独的一个事务管理的时候需要用到REQUIRES_NEW。
例如下面示例中的methodA需要单独开启事务,不受调用方法事务的回滚而回滚:
@transaction
public void testMethod(){
dosomethingBefore...
methodA();
dosomgthingAfter...
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodA(){
updateSomething();
}
假设我们在Controller直接调用testMethod() Spring会帮我们开启一个事务
运行到methodA()这行的时候会挂起当前事务,然后重新创建一个事务,在methodA()中没有发生异常的情况下,运行完methodA方法直接提交methodA的事务;后续再执行dosomgthingAfter。
总共会有4种情况:
- dosomethingBefore发生异常,这时methodA()未运行也就没有事务,直接回滚testMethod()的事务。
- updateSomething发生异常,回滚methodA()的事务,此时如果testMethod()对这个异常进行了try catch捕获,testMethod的事务照常提交。
- updateSomething发生异常,回滚methodA()的事务,此时如果testMethod()没有对这个异常进行try catch捕获,那么methodA和testMethod的事务都会回滚。
- 前面全部正常 dosomgthingAfter 发生异常,这时methodA()事务已经提交 testMethod()所做的修改会回滚。
而Spring中的@Transactional(rollbackFor = Exception.class)事务处理,当你的方法中抛出异常时,它会将
事务回滚,数据库中的数据将不会改变,也就是回到进入此方法前的状态。
网友评论