版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_38111957/article/details/83959696
一、引言
不知道小伙伴们有没有想过这样一个问题,比如说有两个方法,同时都具有事务,如果说其中一个方法调用另外一个方法,那么事务运行的机制是什么样子的。如果被调用的方法正常执行,而调用者确异常了,那么整个事务会进行回滚吗?
针对这么一个问题,Spring还是提供了一个很好的解决办法,也提出一个概念,事务的传播行为。
二、事务的传播行为
当事务方法被另一个事物方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有的事务当中运行,也可能开启一个新的事务,并在自己的事务中运行。
事务的传播行为可以由传播属性指定,Spring定义7中类型传播行为,本章主要介绍两种常用的。
三、具体实现
接着上一章的案例继续,现在需要实现一个功能,可以一次性购买多个商品。
新建一个Service类,如果在同一个类中指定传播行为,是不会生效的。
@Service
public class CheckOutService {
@Autowired
private DataBaseService dataBaseService;
/**
* 一次性购买多个商品
* @param userid 用户编码
* @param cidlist 商品编码
* @return
*/
@Transactional
public int goListShopping(int userid,List<Integer> cidlist){
for (Integer cid : cidlist){
dataBaseService.goShopping(userid,cid);
}
return 1;
}
}
现在呢,为了制造演示效果,还是修改库存的实现方法,只是为了在购买第二个商品时,抛出一个异常。
public int updateStory(int id) {
//加上这么一个操作,只是为了抛出一个异常
if (id == 2){
System.out.println(100/0);
}
String sql = "update tb_commodity set stock = stock - 1 where id = ?";
return jdbcTemplate.update(sql, id);
}
按道理来说,即使在第二次购买的时候出现问题,发现钱不够了,但是可以购买一个商品的。但是默认的事务传播行为可不允许我们这么干。
如果我们使用默认的事务传播行为,则第二次失败后,第一次购买的商品也会被回滚。
修改传播属性为REQUIRES_NEW,当前事务会被挂起,开启新的事务。
这就是事务的传播行为。
@Service
public class DataBaseService {
@Autowired
private DataBaseDao dataBaseDao;
/**
* 购物操作
* @param userid 用户编码,减去该用户账户相对应的购买商品金额
* @param cid 商品编码,查询该商品的价格,以及购买成功是库存-1
*
* 使用propagaion来指定事务的传播行为,默认是REQIORED,表示共用一个事务,即使第一次购买成功,第二次购买失败,但结果还是整个进行回滚
*
* 如果指定传播行为是:REQUIRES_NEW ,则当前事务会被挂起,被调用的方法,开启新的事务。
* 第一购买成功之后就提交了,即使第二次失败了,也和第一次无关
* @return
*/
@Transactional(propagation = Propagation.REQUIRES_NEW)
public int goShopping(int userid,int cid){
//查询商品
Commodity commodity = dataBaseDao.selectCommodityByid(cid);
//减去用户账户金额
dataBaseDao.updateAccount(userid,commodity.getPrice());
//减去该商品的库存
dataBaseDao.updateStory(cid);
return 1;
}
}