事务的传播行为
如果有事务在运行,当前方法就在这个事务内运行,否则,就启动一个新的事务,并在自己的事务内运行
事务方法的嵌套,传播行为可由传播属性决定。
7个传播属性
required和requires_new
required:先坐老王的车,老王翻车就G了。如果老王没车就自己买一辆车。
requires_new:自己买一辆车,只允许存在自己一辆车,如果老王车也在,则暂时挂起老王的车。如果自己的车又出现问题,自己执行失败。
多个方法同时使用requires_new:将老王的车挂起后,执行完自己的方法业务后,开启老王的车继续行驶
@Transactional(propagation= Propagation.REQUIRED)
/@Transactional(propagation= Propagation.REQUIRES_NEW)
public void checkout(String username,String isdn) throws FileNotFoundException {
bookDao.updateStock(isdn);// 减库存
bookDao.updateBalance(username,bookDao.getPrice(isdn));// 减余额
}
@Transactional(propagation = Propagation.REQUIRED)
/@Transactional(propagation= Propagation.REQUIRES_NEW)
public void updatePrice(String isbn,int price){
bookDao.updatePrice(isbn, price);
int i = 10/0;
}
@Transactional
public int getPrice(String isbn){
return bookDao.getPrice(isbn);
}
@Service
public class MultService {
@Autowired
private TxBookService bookService;
@Transactional
public void mulTx() throws FileNotFoundException {
// 嵌套事务一(required)
bookService.checkout("Tom","ISBN-001");
// 嵌套事务二(required),如果发生异常,嵌套事务一是否回滚都需要设置(使用传播行为)设置这个事务方法是不是和之前的大事务共享一个事务(使用同一条连接)
bookService.updatePrice("ISBN-002",520);
int i = 10/0;
}
}
**
* 多事务
*/
@Test
public void test2() throws FileNotFoundException {
MultService multService = ioc.getBean(MultService.class);
multService.mulTx();
}
因为更改价格updatePrice()出现异常,事务全部回滚。
而如果只在结账checkout中使用propagation=Propagation.REQUIRES_NEW,则结账不回滚,更改价格回滚
而如果只在更改价格updatePrice()中使用propagation=Propagation.REQUIES_NEW,则结账回滚,更改价格因出现异常更改失败。
而如果同时在checkout()和updatePrice()中都使用propagation=Propagation.REQUIES_NEW,则结账不回滚,更改价格因出现异常更改失败。
而如果同时在checkout()和updatePrice()中都使用propagation=Propagation.REQUIED,且如果在mulTx()中出现了错误,则都回滚(全在一辆车都翻了会滚了)
而如果在结账中使用propagation=Propagation.REQUIRED,在更改价格中使用propagation=Propagation.REQUIES_NEW,且如果在mulTx()中出现了错误,则结账因为被挂起无效无现象(回滚)而更改价格方法中未出现异常但multx()大体事务中出现了错误,导致只有更改价格更改程度不回滚
multx(){
// required
A(){
// requires_new
B(){}
// required
C(){}
}
// requires_new
D(){
// requires_new 不崩
// required 崩
DDDD(){}
E(){
// requires_new
F(){
int i = 10/0;(E/G /A/C崩)
}
}
// requires_new
G(){}
}
int i=10/0; (B成功,D整个分支全部成功)
}
结论1:任何处崩,已经执行的requires_new都成功不崩。
如果是required,事务的属性继承于最大事务,在传播行为下的timeout必须设置在原始父事务方法中,才会有超时异常。设置在其他地方等于没设。
如果是requires_new,timeout就设置在当前事务方法就可。
底层:
required:将之前事务用的connection传递给当前方法使用
requires_new:这个方法直接使用新的connection