在一般的交易类程序中会频繁的使用事务来约束重要或关键的动作,已保证交易行为的整体性和一致性。
下例中是在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;
}
程序中先查询数据库中是否已有相同的订单号以避免重复订单,查询没有相同的订单号后将传入参数入库。本例中将着两个过程设置在一个事务中。