在一般的交易类程序中会频繁的使用事务来约束重要或关键的动作,已保证交易行为的整体性和一致性。
下例中是在Spring框架下中使用JDBC连接数据库的事务示例。
1.配置文件内容
数据源、事务的底层配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <bean id="dataSource" class="org.logicalcobwebs.proxool.ProxoolDataSource"> <property name="driver" value="oracle.jdbc.OracleDriver" /> <property name="driverUrl" value="jdbc:oracle:thin:@127.0.0.1:1523:NTDATA" /> <!-- property name="driverUrl" value="jdbc:oracle:thin:@(DESCRIPTION =(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.31.1)(PORT = 1521))(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.31.2)(PORT = 1521))(LOAD_BALANCE = OFF)(FAILOVER=ON)(CONNECT_DATA =(SERVER = DEDICATED)(SERVICE_NAME = zfpay1)(FAILOVER_MODE=(TYPE = SELECT)(METHOD = BASIC)(RETIRES = 20)(DELAY = 15))))" /> --> <property name="user" value="jfb3" /> <property name="password" value="jfb3" /> <property name="alias" value="ecpay" /> <property name="maximumActiveTime" value="300000" /> <property name="prototypeCount" value="0" /> <property name="maximumConnectionCount" value="50" /> <property name="minimumConnectionCount" value="2" /> <property name="simultaneousBuildThrottle" value="50" /> <property name="houseKeepingTestSql" value="select 1 from dual" /> </bean> <!-- jdbc事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource"> <ref local="dataSource" /> </property> </bean> <!--事务模板 --> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager"> <ref local="transactionManager" /> </property> <!--ISOLATION_DEFAULT 表示由使用的数据库决定 --> <property name="isolationLevelName" value="ISOLATION_DEFAULT"/> <property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"/> <!-- <property name="timeout" value="30"/> --> </bean> <!-- 启动使用注解实现声明式事务管理的支持 <tx:annotation-driven transaction-manager="txManager" /> --> </beans>
DAO层的配置
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/> </bean> <bean id="sequence8" class="org.springframework.jdbc.support.incrementer.OracleSequenceMaxValueIncrementer"> <property name="incrementerName" value="EPAY_SEQUENCE_8" /> <property name="dataSource" ref="dataSource"/> </bean> <bean id="merchantMapDAO" class="cn.com.nantian.epayment.dao.MerchantMapDAO"> <property name="jdbcTemplate" ref="jdbcTemplate"/> </bean> <bean id="payOrderDAO" class="cn.com.nantian.epayment.dao.PayOrderDAO"> <property name="jdbcTemplate" ref="jdbcTemplate"/> </bean>SERVICE层的配置
<bean id="elecChnlFrontPayService" class="cn.com.nantian.epayment.pay.service.ElecChnlFrontPayServiceImpl"> <property name="merchantMapDAO" ref="merchantMapDAO" /> <property name="payOrderDAO" ref="payOrderDAO" /> <property name="transactionTemplate" ref="transactionTemplate" /> </bean>
private PayOrderDAO payOrderDAO; protected TransactionTemplate transactionTemplate; /** * 保存支付订单 */ protected PayOrder savePayReq(final PayOrder payOrder) { PayOrder order = (PayOrder) this.transactionTemplate .execute(new TransactionCallback() { @Override public Object doInTransaction(TransactionStatus status) { // 查看是否已经存在支付订单,如果已经存在则返回订单主键 PayOrder payOrderTemp = payOrderDAO.findOrder(String .valueOf(payOrder.getPayOrderId())); // 由支付渠道类型(PayChannelType)转换得到交易类型(PayType) if (payOrder.getPayChannelId().equalsIgnoreCase(PAY_CHNL_ACT_BAL)) {// 账户余额支付 payOrder.setPayType("3"); } else if (payOrder.getPayChannelId().equalsIgnoreCase(PAY_CHNL_FAST_PAY)) {// 联通快捷支付 payOrder.setPayType("4"); } else {// 网银网关支付 payOrder.setPayType("2"); } // 比对新的支付金额与原订单金额是否一致,如不一致则提示错误 if (payOrderTemp == null) { String orderId = payOrderDAO.save(payOrder); payOrder.setPayOrderId(orderId); return payOrder; } else { return payOrderTemp; } } }); if ("2".equals(order.getOrderState())) {// 2:表示支付成功 throw new EpaymentBizException(StatusCode.DQSystem.PAY_FAIL, "同一订单不能重复支付"); } else if (payOrder.getPayAmt().longValue() != order.getPayAmt() .longValue()) { throw new EpaymentBizException(StatusCode.DQSystem.PAY_FAIL, "交易金额与原订单不一致"); } else { return payOrder; } } public PayOrderDAO getPayOrderDAO() { return payOrderDAO; } public void setPayOrderDAO(PayOrderDAO payOrderDAO) { this.payOrderDAO = payOrderDAO; } public TransactionTemplate getTransactionTemplate() { return transactionTemplate; } public void setTransactionTemplate(TransactionTemplate transactionTemplate) { this.transactionTemplate = transactionTemplate; }程序中先查询数据库中是否已有相同的订单号以避免重复订单,查询没有相同的订单号后将传入参数入库。本例中将着两个过程设置在一个事务中。