REQUIRED:
默认值,如果有事务在运行,当前的方法就在这个事务内运行,否则,就启动一个新的事务,并在自己的事务内运行
-
测试类:
场景:一个人(id为aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa)的钱包有100元,它想买两类书,第一类id为a2f39533-659f-42ca-af91-c688a83f6e49,数量为1本,单价为10元,该书库存为10本;第二类id为4c37672a-653c-4cc8-9ab5-ee0c614c7425,数量为10,单价为10元,该书库存为10本;package com.jd.test; import java.util.*; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.jd.car.ICarService; import com.jd.car.imp.CarService; public class Test { public static void main(String[] args) { ClassPathXmlApplicationContext application = new ClassPathXmlApplicationContext("application.xml"); ICarService carService = application.getBean(CarService.class); String userId = "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"; Map<String,Integer> commodities = new HashMap<String,Integer>(); commodities.put("a2f39533-659f-42ca-af91-c688a83f6e49",1); commodities.put("4c37672a-653c-4cc8-9ab5-ee0c614c7425",10); carService.batch(userId, commodities); application.close(); } }
-
CarService类
package com.jd.car.imp; import java.util.*; import java.util.Map.Entry; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.jd.car.ICarService; import com.jd.coupon.ICouponService; @Service public class CarService implements ICarService { @Autowired private ICouponService couponService; //购物车购买 @Override @Transactional public boolean batch(String userId,Map<String,Integer> commodities) { Set<Entry<String, Integer>> set = commodities.entrySet(); for (Entry<String, Integer> commodity : set) { String bookId = commodity.getKey(); int count = commodity.getValue(); System.out.println(bookId+","+count); couponService.insert(userId,bookId, count); } return true; } }
-
CouponService类
package com.jd.coupon.imp; import java.util.*; import java.util.Map.Entry; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import com.jd.book.IBookDao; import com.jd.coupon.ICouponDao; import com.jd.coupon.ICouponService; import com.jd.money.IMoneyDao; import com.jd.vo.Coupon; @Service public class CouponService implements ICouponService { @Autowired private IBookDao bookDao; @Autowired private IMoneyDao moneyDao; @Autowired private ICouponDao couponDao; //立即购买 @Override @Transactional/*(propagation=Propagation.REQUIRED)*/ public boolean insert(String userId,String bookId, int count){ if(bookDao.enough(bookId, count)) {//书籍足够 //书籍表库存递减 bookDao.update(bookId, count); } double price = bookDao.getPrice(bookId); double total = price*count; if(moneyDao.enough(userId, total)) {//余额足够 //订单表添加数据 Coupon coupon = new Coupon(); coupon.setId(UUID.randomUUID().toString()); coupon.setUserId(userId); coupon.setBookId(bookId); coupon.setTotal(total); couponDao.insert(coupon); //钱包表递减 moneyDao.update(userId, total); } return true; } }
分析:
事务方法insert被另一个事务方法batch调用时,事务方法insert默认在batch方法的事务内运行,即insert方法和batch方法在同一个事务中(相当于修饰insert方法的@Transactional注解中添加了“propagation=Propagation.REQUIRED”属性),因此结算第二类书籍时钱包钱不够,insert方法抛出了异常以至于insert方法和batch方法所在的事务进行了回滚,最终导致第一类书籍的结算也时效。