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 }
时间: 2024-10-12 23:47:33