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方法所在的事務進行了回滾,最終導致第一類書籍的結算也時效。