假如有两个方法A和B,A调用B,这两个方法上都加了事物,究竟使用哪个事物?
Public void A(){
B();
}
这就是spring事物传播行为要解决的问题。
在spring中有七种事务传播行为。
简单介绍一下这七种方式(如果不懂不用纠结,后面详细介绍)
常用:
REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中,一般的选择(默认值)
REQUIRES_NEW : 新建事务,如果当前在事务中,把当前事务挂起。
不常用:
SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务)
MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常
NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
NEVER:以非事务方式运行,如果当前存在事务,抛出异常
NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行 REQUIRED 类似的操作。
我们重点介绍一下常用的两种:
一:REQUIRED :
方法B用REQUIRED修饰,方法A调用方法B,如果方法A当前没有事务,方法B就新建一个事务,如果方法A有事务,方法B就加入到这个事务中。一般的选择(默认值)
下面来看一个转账的例子:
数据库:
数据访问层:
@Repository("accountDao")
public class AccountDaoImpl{
updateAccount(Account account) { jdbcTemplate.update(,account.getMoney(),account.getId()); }
}
业务逻辑层:
@Service("accountService")
public class AccountServiceImpl{
@Transactional(propagation=Propagation.REQUIRED)
transfer(Account source, Account target, Float money) { source.setMoney(source.getMoney()-money);target.setMoney(target.getMoney()+money);.updateAccount(source); .updateAccount(target); }
@Transactional(propagation=Propagation.REQUIRED)
transferException(Account source, Account target, Float money) { source.setMoney(source.getMoney()-money);target.setMoney(target.getMoney()+money);.updateAccount(source); i=1/0; .updateAccount(target); }
}
测试:
@Test public voidtestDo(){ serviceImpl.transfer("%张%","%李%",1000f);
serviceImpl.transferException ("%张%","%李%",2000f);
int I = 1/0; }
现在测试的方法testDo上没有加事务,当它调用serviceImpl.transfer()方法的时候,因为transfer使用REQUIRED修饰,所以transfer会新建一个事务,自己独立在该事务执行,成功转账1000,张三账户1000,李四4000。当调用serviceImpl.transferException时新建事务,在执行该方法时发生异常,事务回滚,所以转账不成功,张三账户1000,李四4000,此时这两个方法都是在自己的事务中独立执行。
现在把testDo方法上也加上事务
再来测试一下:
@Test
public voidtestDo(){ serviceImpl.transfer("%张%","%李%",1000f);
serviceImpl.transferException ("%张%","%李%",2000f);
}
当它调用serviceImpl.transfer()方法的时候transfer方法和transferException方法加入到testDo方法的事务中,他们都在一个事务,当发生异常的时候事务回滚,转账1000和2000都不成功,张三账户2000,李四3000。
二:REQUIRES_NEW:
方法B用REQUIRES_NEW修饰,方法A调用方法B,不管方法A上有没有事务方法B都新建一个事务,在该事务执行。
测试:
@Test public voidtestDo(){ serviceImpl.transfer("%张%","%李%",1000f);
serviceImpl.transferException ("%张%","%李%",2000f);
int I = 1/0; }
不管testDo方法上有没有事务,“serviceImpl.transfer”方法和“serviceImpl.transferException”方法都会新建事务,独立在各自的事务中执行,互不影响,所以转账1000成功,转账2000失败。结果是:张三账户1000,李四4000