以前我們說過默穴,Spring通過ThreadLocal機(jī)制解除了事務(wù)管理模塊與數(shù)據(jù)訪問層的緊密耦合床绪,提高了模塊的可重用性,也保證了多線程環(huán)境下的對connection資源的有效管理,實(shí)現(xiàn)了線程安全。而要將事務(wù)管理代碼從整個業(yè)務(wù)邏輯中抽離出來巫俺,提供系統(tǒng)性的服務(wù),就要使用Spring aop肿男,在使用過程中介汹,我們千萬不可忘記了其動態(tài)代理的實(shí)質(zhì),不然在使用過程你會不知不覺掉進(jìn)陷阱里舶沛,請看以下例子:
(1) 正常情況
外部調(diào)用:
orderService.addOrder(order,orderDto);
Service內(nèi)的addOrder方法:
@Override
@Transactional
public void addOrder(Order order,OrderDto orderDto) throws Exception {
orderDAO.addOrder(order);
OrderDetail orderDetail = new OrderDetail();
orderDetail.setDiscount(orderDto.getDiscount());
orderDetail.setQuantity(orderDto.getQuantity());
Product productParam = new Product();
productParam.setProductId(orderDto.getProductId());
Product productGet = productService.getProducts(productParam).get(0);
orderDetail.setProduct(productGet);
productGet.getOrderDetail().add(orderDetail);
orderDetail.setOrder(order);
order.getOrderDetails().add(orderDetail);
productGet.setQuantity(productGet.getQuantity()-orderDetail.getQuantity());
orderDetailDAO.addOrderDetail(orderDetail);
throw new RuntimeException("it's wrong");
}
添加訂單前數(shù)據(jù):
添加訂單后數(shù)據(jù):
拋出異常嘹承,事務(wù)回滾,操作后表記錄未變如庭。
(2) 非正常情況
外部調(diào)用:
orderService.addOrderWrapper(order,orderDto);
@Override
public void addOrderWrapper(Order order,OrderDto orderDto) throws Exception{
//(1)中的addOrder方法,仍然有@Transactional注解
addOrder(order, orderDto);
}
執(zhí)行后數(shù)據(jù)
雖然拋出異常叹卷,但事務(wù)未回滾,操作后數(shù)據(jù)改變了。
為什么在orderService的addOrderWrapper()方法內(nèi)部調(diào)用addOrder(),報運(yùn)行時異常時就不會回滾了呢? 實(shí)際上豪娜,在第一種情況中餐胀,程序是通過orderService的代理類上調(diào)用addOrder()方法的哟楷,這樣瘤载,與該方法相關(guān)的攔截器就會對請求進(jìn)行攔截處理,提供相應(yīng)的事務(wù)處理機(jī)制卖擅;而在第二種情況下鸣奔,addOrder()方法雖然仍然有@Transaction注解,但僅僅是在orderService上的直接調(diào)用惩阶,而不是通過代理類調(diào)用挎狸,偽代碼的形式展現(xiàn)如下:
第一種情況:
ProxyFactory factory = new ProxyFactory(orderServiceImpl);
factory.addInterceptor(transactionInterceptor);
OrderService proxy = (orderService) factory.getProxy();
proxy.addOrder();//通過代理調(diào)用
第二種情況:
同this.addOrder();//直接通過this調(diào)用,事務(wù)攔截方法不起作用断楷。
在事務(wù)代理類上調(diào)用方法的過程見如圖:
(圖1-1 來源:spring-framework-reference)
無論Spring聲明式事務(wù)使用什么形式(基于Xml配置文件或者Annotation),萬變不離其宗,其底層都是使用了TransactionInterceptor锨匆。TransactionInterceptor是一個實(shí)現(xiàn)了MethodInterceptor接口的攔截器(Advice),具有相應(yīng)的事務(wù)橫切邏輯冬筒,被織入到系統(tǒng)中恐锣。若方法聲明了相應(yīng)的事務(wù)控制信息,它會在該方法執(zhí)行前開啟一個事務(wù)舞痰,完成時提交事務(wù)土榴,發(fā)生異常時回滾事務(wù),至于其中的具體規(guī)則(傳播响牛,隔離級別玷禽,超時時間,是否只讀呀打,針對何種異常進(jìn)行回滾)矢赁,可以通過xml或者@Transactional指定。
如圖就是它實(shí)現(xiàn)的invoke方法的源代碼:
createTransactionIfNecessary方法將會開啟一個事務(wù)贬丛;斷點(diǎn)處的proceed方法讓程序沿著調(diào)用鏈傳播(如圖1-1所示)撩银。completeTransactionAfterThrowing和commitTransactionAfterReturning方法則提交回滾事務(wù)。