Spring事務管理的另一種方式--TransactionTemplate編程式事務管理簡單入門
1, 一直以來, 在用Spring進行事物管理時, 只知道用聲明式的策略, 即根據不同的數據源, 配置一個事物管理器(TransactionManager), 通過配置切面(PointCut)應用到相應的業務方法上或者直接在方法上加@Ttransactional注解.
這種事務管理使用起來比較簡單,但個人感覺靈活性欠缺了點.
2, 最近看公司項目代碼, 發現有位同事在他的模塊了用了另外一種事務管理方式, 查了一下,TransactionTemplate是編程式事務管理.需要自己手動在每個業務方法中實現事務.
3, TransactionTemplate使用(不一定全面):
A, 在DAO層的配置文件中, 配置TransactionTemplate, 需要注入TransactionManager
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager"> <ref bean="transactionManager"/> </property> </bean>
B, 將TransactionTemplate注入到業務層方法中, 並使用:
首先分析一下TransactionTemplate的核心原理:
TransactionTemplate核心方法:
1 public class TransactionTemplate extends DefaultTransactionDefinition 2 implements TransactionOperations, InitializingBean { 3 4 5 public <T> T execute(TransactionCallback<T> action) throws TransactionException { 6 if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) { 7 return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action); 8 } 9 else { 10 TransactionStatus status = this.transactionManager.getTransaction(this); 11 T result; 12 try { 13 result = action.doInTransaction(status); 14 } 15 catch (RuntimeException ex) { 16 // Transactional code threw application exception -> rollback 17 rollbackOnException(status, ex); 18 throw ex; 19 } 20 catch (Error err) { 21 // Transactional code threw error -> rollback 22 rollbackOnException(status, err); 23 throw err; 24 } 25 catch (Exception ex) { 26 // Transactional code threw unexpected exception -> rollback 27 rollbackOnException(status, ex); 28 throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception"); 29 } 30 this.transactionManager.commit(status); 31 return result; 32 } 33 }
由上面的代碼可以推測到, 真正執行業務方法的關鍵代碼是: action.doInTransaction(status);
正好, 有個入參TransactionCallback<T>, 翻看該接口的源碼:
1 public interface TransactionCallback<T> { 2 5 T doInTransaction(TransactionStatus status); 6 7 }
該接口只有一個doInTransaction方法, 那么很簡單, 我們可以通過匿名內部類的方式將業務代碼放在doInTransaction中:
舉例如下:
1 private PayOrderDAO payOrderDAO; 2 3 protected TransactionTemplate transactionTemplate; 4 5 /** 6 * 保存支付訂單 7 */ 8 protected PayOrder savePayReq(final PayOrder payOrder) { 9 10 @Autowired 11 private TransactionTemplate transactionTemplate; 12 13 @Autowired 14 private PayOrderDAO payOrderDAO; 15 16 PayOrder order = (PayOrder) this.transactionTemplate 17 .execute(new TransactionCallback() { 18 @Override 19 public Object doInTransaction(TransactionStatus status) { 20 // 查看是否已經存在支付訂單,如果已經存在則返回訂單主鍵 21 PayOrder payOrderTemp = payOrderDAO.findOrder(String 22 .valueOf(payOrder.getPayOrderId())); 23 24 // 由支付渠道類型(PayChannelType)轉換得到交易類型(PayType) 25 if (payOrder.getPayChannelId().equalsIgnoreCase(PAY_CHNL_ACT_BAL)) {// 賬戶余額支付 26 payOrder.setPayType("3"); 27 } else if (payOrder.getPayChannelId().equalsIgnoreCase(PAY_CHNL_FAST_PAY)) {// 聯通快捷支付 28 payOrder.setPayType("4"); 29 } else {// 網銀網關支付 30 payOrder.setPayType("2"); 31 } 32 33 // 比對新的支付金額與原訂單金額是否一致,如不一致則提示錯誤 34 if (payOrderTemp == null) { 35 String orderId = payOrderDAO.save(payOrder); 36 payOrder.setPayOrderId(orderId); 37 return payOrder; 38 } else { 39 return payOrderTemp; 40 } 41 } 42 }); 43 if ("2".equals(order.getOrderState())) {// 2:表示支付成功 44 throw new EpaymentBizException(StatusCode.DQSystem.PAY_FAIL, 45 "同一訂單不能重復支付"); 46 } else if (payOrder.getPayAmt().longValue() != order.getPayAmt() 47 .longValue()) { 48 throw new EpaymentBizException(StatusCode.DQSystem.PAY_FAIL, 49 "交易金額與原訂單不一致"); 50 } else { 51 return payOrder; 52 } 53 54 }
轉自:https://www.cnblogs.com/wyisprogramming/p/6944878.html