27. 代码实例-spring声明式事务

(1)spring配置文件:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
 3     xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util"
 4     xsi:schemaLocation="   
 5    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd   
 6    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd   
 7    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd   
 8  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd    
 9 http://www.springframework.org/schema/util classpath:/org/springframework/beans/factory/xml/spring-util-3.0.xsd
10  "
11     default-autowire="byName">
12     <bean id="paymentSqlSqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
13         <property name="configLocation" value="classpath:sqlmap/sqlserver/sqlserver-consume.xml" />
14         <property name="dataSource" ref="paymentSqlDataSource" />
15     </bean>
16 
17     <!-- ============================ payment ======================================= -->
18     <bean id="paymentSqlDataSource" class="org.apache.commons.dbcp.BasicDataSource">
19         <property name="driverClassName" value="${sqlserver.jdbc.driver}" />
20         <property name="url" value="${payment.sqlserver.jdbc.url}" />
21         <property name="username" value="${payment.sqlserver.jdbc.username}" />
22         <property name="password" value="${payment.sqlserver.jdbc.password}" />
23         <property name="maxActive" value="30" />
24         <property name="initialSize" value="2" />
25         <property name="maxWait" value="60000" />
26         <property name="maxIdle" value="30" />
27         <property name="minIdle" value="1" />
28         <property name="testOnBorrow" value="false"></property>
29         <property name="testWhileIdle" value="true"></property>
30         <property name="validationQuery" value="select 1 "></property>
31         <property name="timeBetweenEvictionRunsMillis">
32             <value>300000</value>
33         </property>
34         <property name="numTestsPerEvictionRun">
35             <value>10</value>
36         </property>
37         <property name="minEvictableIdleTimeMillis" value="300000"></property>
38     </bean>
39      <bean id="consumeTemplate"  class="org.springframework.orm.ibatis.SqlMapClientTemplate" >  
40         <property name="sqlMapClient" ref="paymentSqlSqlMapClient" />  
41     </bean> 
42     <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
43         <property name="dataSource" ref="paymentSqlDataSource" />
44     </bean>
45     <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
46 </beans>

 (2)事务相关代码

 1 package com.jd.consume.service.consume.impl;
 2 
 3 import java.util.List;
 4 
 5 import javax.annotation.Resource;
 6 
 7 import org.apache.commons.collections.CollectionUtils;
 8 import org.slf4j.Logger;
 9 import org.slf4j.LoggerFactory;
10 import org.springframework.stereotype.Service;
11 import org.springframework.transaction.annotation.Propagation;
12 import org.springframework.transaction.annotation.Transactional;
13 
14 import com.jd.consume.dao.ConsumeDao;
15 import com.jd.consume.dao.OrderTaskDao;
16 import com.jd.consume.domain.ConsumeDetail;
17 import com.jd.consume.domain.OrderTask;
18 import com.jd.consume.service.consume.ConsumeChange;
19 
20 /**
21  * 消费额度变更服务
22  * @author guanpanpan
23  *
24  */
25 @Service(value = "consumeChange")
26 @Transactional(value = "transactionManager", readOnly = true)
27 public class ConsumeChangeImpl implements ConsumeChange {
28     protected final static Logger log = LoggerFactory.getLogger(ConsumeChangeImpl.class);
29     @Resource
30     private OrderTaskDao orderTaskDao;
31     @Resource
32     private ConsumeDao consumeDao;
33     public static boolean throwRuntimeExceptionInTransation = false;
34 
35     @Transactional(value = "transactionManager", readOnly = false, rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
36     public void addConsumeWithSingleTask(OrderTask orderTask) {
37         ConsumeDetail consumeDetail = orderTask.genAddConsumeDetail();
38         //防止重复执行,如果存在uuid置状态为11
39         List<ConsumeDetail> consumeDetails = consumeDao.findConsumeDetailsByUuid(consumeDetail.getUuId());
40         if (CollectionUtils.isNotEmpty(consumeDetails)) {
41             orderTaskDao.updateStatus(orderTask.getId(), OrderTask.SYN_REPEAT, OrderTask.SYN_LOCK);
42             return;
43         }
44         consumeDao.addConsumeDetail(consumeDetail);
45         consumeDao.insertOrUpdateJdConsume(consumeDetail);
46         //设置状态为已处理,如果失败会在回滚中置好状态
47         orderTaskDao.updateStatus(orderTask.getId(), OrderTask.SYN_COMPLETE, OrderTask.SYN_LOCK);
48         if (throwRuntimeExceptionInTransation) {
49             throw new RuntimeException("rollBack in Test");
50         }
51     }
52 
53     @Override
54     @Transactional(value = "transactionManager", readOnly = false, rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
55     public void reduceConsumeWithSingleTask(OrderTask orderTask) {
56         ConsumeDetail consumeDetail = orderTask.genPastConsumeDetail();
57         //防止重复执行,如果存在uuid置状态为12
58         List<ConsumeDetail> consumeDetails = consumeDao.findConsumeDetailsByUuid(consumeDetail.getUuId());
59         if (CollectionUtils.isNotEmpty(consumeDetails)) {
60             orderTaskDao.updatePastStatus(orderTask.getId(), OrderTask.PAST_REPEAT, OrderTask.PAST_LOCK);
61             return;
62         }
63         //设置状态为已处理,如果失败会在回滚中置好状态
64         orderTaskDao.updatePastStatus(orderTask.getId(), OrderTask.PAST_DUE_YET, OrderTask.PAST_LOCK);
65         consumeDao.addConsumeDetail(consumeDetail);
66         consumeDao.insertOrUpdateJdConsume(consumeDetail);
67         if (throwRuntimeExceptionInTransation) {
68             throw new RuntimeException("rollBack in Test");
69         }
70 
71     }
72 
73 }

 

(3)编码式事务

有时不能使用声明时事务,比如分库分表。声明式的库是固定的。

  1 package com.jd.consume.service.consume.impl;
  2 
  3 import java.util.HashSet;
  4 import java.util.Set;
  5 
  6 import javax.annotation.Resource;
  7 
  8 import org.slf4j.Logger;
  9 import org.slf4j.LoggerFactory;
 10 import org.springframework.jdbc.datasource.DataSourceTransactionManager;
 11 import org.springframework.stereotype.Service;
 12 import org.springframework.transaction.TransactionDefinition;
 13 import org.springframework.transaction.TransactionStatus;
 14 import org.springframework.transaction.support.DefaultTransactionDefinition;
 15 import org.springframework.util.CollectionUtils;
 16 
 17 import com.jd.consume.dao.moredb.DbManager;
 18 import com.jd.consume.dao.mysql.ConsumeDaoMysql;
 19 import com.jd.consume.dao.mysql.ConsumeDetailDaoMysql;
 20 import com.jd.consume.dao.mysql.OrderTaskDaoMysql;
 21 import com.jd.consume.domain.ConsumeDetail;
 22 import com.jd.consume.domain.JdConsume;
 23 import com.jd.consume.domain.OrderTask;
 24 import com.jd.consume.service.consume.CalJdconsume;
 25 import com.jd.consume.service.consume.ConsumeChange;
 26 import com.jd.consume.util.LogUtil;
 27 import com.jd.consume.util.PropertyUtil;
 28 
 29 /**
 30  * 消费额度变更服务
 31  * @author guanpanpan
 32  *
 33  */
 34 @Service(value = "consumeChange")
 35 //@Transactional(value = "transactionManager", readOnly = true)
 36 public class ConsumeChangeImpl implements ConsumeChange {
 37     protected final static Logger log = LoggerFactory.getLogger(ConsumeChangeImpl.class);
 38     @Resource
 39     private OrderTaskDaoMysql orderTaskDaoMysql;
 40     @Resource
 41     private ConsumeDaoMysql consumeDaoMysql;
 42     @Resource
 43     private ConsumeDetailDaoMysql consumeDetailDaoMysql;
 44     @Resource
 45     private DbManager dbManager;
 46     @Resource(name = "calJdconsumeFind")
 47     private CalJdconsume calJdconsumeFind;
 48     @Resource(name = "calJdconsumeCal")
 49     private CalJdconsume calJdconsumeCal;
 50     private boolean calJdconsumeByFind = PropertyUtil.getBooleanParameter("calJdconsumeByFind");//默认用数据库计算,减少传输
 51     public static boolean throwRuntimeExceptionInTransation = false;
 52     public static ThreadLocal<Set<String>> reDianPin = new ThreadLocal<Set<String>>();//热点数据
 53     public static ThreadLocal<Long> reDianLastTime = new ThreadLocal<Long>();//热点数据
 54     public static boolean isReDianFlag = true;
 55     public static int reDianExePerTime = 5;//分钟,每几分钟执行一下热点
 56     public static int reDianMomeryMax = 100;//最多缓存热点数据
 57     public static boolean isUpGrade = false;//是否需要升级,新版本升级程序上线后就不需要再升级了
 58 
 59     //@Transactional(value = "transactionManager", readOnly = false, rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
 60     public void addConsumeWithSingleTask(int dbNo, OrderTask orderTask) {
 61         //因为分库所以不能用注解
 62         DefaultTransactionDefinition def = new DefaultTransactionDefinition();
 63         def.setReadOnly(false);
 64         def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
 65         DataSourceTransactionManager transactionManager = dbManager.getTransactionManager(dbNo);
 66         TransactionStatus status = transactionManager.getTransaction(def);
 67         try {
 68             ConsumeDetail consumeDetail = orderTask.genAddConsumeDetail();
 69             //防止重复执行,如果存在uuid置状态为11
 70             ConsumeDetail consumeDetailDb = consumeDetailDaoMysql
 71                     .findConsumeDetailsByUuid(orderTask.getPin(), consumeDetail.getUuId());
 72             if (null != consumeDetailDb) {
 73                 orderTaskDaoMysql.updateStatus(dbNo, orderTask.getId(), OrderTask.SYN_REPEAT, OrderTask.SYN_LOCK);
 74                 transactionManager.commit(status);
 75                 return;
 76             }
 77             consumeDetailDaoMysql.addConsumeDetail(consumeDetail);
 78             if (isReDianFlag) {
 79                 JdConsume jdConsume = consumeDaoMysql.getJdConsumeByPin(orderTask.getPin());
 80                 if (null == jdConsume || !jdConsume.isReDian()) {
 81                     calAndSaveJdConsumeAmounts(orderTask.getPin());//计算消费额度
 82                     //设置状态为已处理,如果失败会在回滚中置好状态
 83                     updateAddStatus(dbNo, orderTask);
 84                 } else {
 85                     //加入热点集合去重
 86                     Set<String> reDianSet = reDianPin.get();
 87                     if (reDianSet == null) {
 88                         reDianSet = new HashSet<String>();
 89                     }
 90                     reDianSet.add(orderTask.getPin());
 91                     reDianPin.set(reDianSet);
 92                     //设置时间
 93                     if (reDianLastTime.get() == null) {
 94                         reDianLastTime.set(System.currentTimeMillis());
 95                     }
 96                     //设置状态为已处理,如果失败会在回滚中置好状态
 97                     orderTaskDaoMysql.updateStatus(dbNo, orderTask.getId(), OrderTask.SYN_REDIAN_ADD, OrderTask.SYN_LOCK);
 98 
 99                 }
100             } else {
101                 calAndSaveJdConsumeAmounts(orderTask.getPin());//计算消费额度
102                 updateAddStatus(dbNo, orderTask);
103             }
104 
105             if (throwRuntimeExceptionInTransation) {
106                 throw new RuntimeException("rollBack in Test");
107             }
108         } catch (Exception e) {
109             transactionManager.rollback(status);
110             throw new RuntimeException(e);
111         }
112         transactionManager.commit(status);
113     }
114 
115     private void updateAddStatus(int dbNo, OrderTask orderTask) {
116         if (isUpGrade) {
117             orderTaskDaoMysql.updateStatus(dbNo, orderTask.getId(), OrderTask.SYN_COMPLETE, OrderTask.SYN_LOCK);
118         } else {
119             orderTaskDaoMysql.updateStatusNoGrade(dbNo, orderTask.getId(), OrderTask.SYN_COMPLETE, OrderTask.SYN_LOCK);
120         }
121 
122     }
123 
124     private void updateAddStatusRedian(int dbNo, String pin) {
125         if (isUpGrade) {
126             orderTaskDaoMysql.updateStatus(dbNo, pin, OrderTask.SYN_COMPLETE, OrderTask.SYN_REDIAN_ADD);
127         } else {
128             orderTaskDaoMysql.updateStatusNoGrade(dbNo, pin, OrderTask.SYN_COMPLETE, OrderTask.SYN_REDIAN_ADD);
129         }
130 
131     }
132 
133     @Override
134     public void dealRedianDatas(int dbNo, int threadId) {
135         Set<String> reDianSet = reDianPin.get();
136         if (CollectionUtils.isEmpty(reDianSet)) {
137             return;
138         }
139 
140         //5分钟执行一次
141         boolean isTime = (System.currentTimeMillis() - reDianLastTime.get()) > 1000 * 60 * reDianExePerTime;
142         if (isTime || reDianSet.size() > reDianMomeryMax) {
143             for (String pin : reDianSet) {
144                 calAndSaveJdConsumeAmounts(pin);//计算消费额度
145                 updateAddStatusRedian(dbNo, pin);
146             }
147             //重置时间
148             reDianLastTime.set(System.currentTimeMillis());
149             //重置集合
150             reDianPin.set(new HashSet<String>());
151             LogUtil.error(LogUtil.ADDCONSUME, "reDian:" + isTime + reDianSet);
152             LogUtil.error(LogUtil.DT, "reDian:" + isTime + "-" + dbNo + "-" + threadId + reDianSet);
153         }
154     }
155 
156     @Override
157     public void calAndSaveJdConsumeAmounts(String pin) {
158         JdConsume jdConsume = calJdconsume(pin);
159         consumeDaoMysql.insertOrUpdateJdConsume(jdConsume);
160     }
161 
162     @Override
163     public JdConsume calJdconsume(String pin) {
164         if (calJdconsumeByFind) {
165             return calJdconsumeFind.calJdconsume(pin);
166         } else {
167             return calJdconsumeCal.calJdconsume(pin);
168         }
169 
170     }
171 
172 }

注:1,2代码来源于consume-grade-sql,3来源于consume-grade-final(mysql版本)

posted on 2013-11-08 16:38  关攀攀  阅读(241)  评论(0)    收藏  举报

导航