使用入门-数据源配置

  • 数据源配置,tddl的入口,从datasource切入
  1. <bean id="tddlDataSource" class="com.taobao.tddl.client.jdbc.TDataSource" init-method="init">
  2. <property name="appName" value="tddl_sample" />
  3. <property name="dynamicRule" value="true"/>
  4. </bean>
  • Sequence生成器
  1. <bean id="seqStudent" class="com.taobao.tddl.client.sequence.impl.GroupSequence" init-method="init">
  2. <property name="sequenceDao" ref="idSequenceDao" />
  3. <property name="name" value="seq_Student" />
  4. </bean>
  • 指定静态文件,3.0以后支持动态推送
  1. <bean id="myDataSource" class="com.taobao.tddl.client.jdbc.TDataSource" init-method="init">
  2. <property name="appName" value="tddl_sample"/>
  3. <property name="appRuleFile" value="classpath:tddl-rule.xml"/>
  4. <property name="useLocalConfig" value="true"/>
  5. </bean>

myDataSource--分库分表数据源

appName--数据库代号从dba获得

appRuleFile--分库分表配置文件

useLocalConfig--使用本地配置

  • Sequence配置:  tddl-sequence.xml
  1. <bean id="sequenceDao" class="com.taobao.tddl.client.sequence.impl.GroupSequenceDao" init-method="init">
  2. <!-- appName,必填 -->
  3. <property name="appName" value="CUNTAO_SUPPLIER_APP" />
  4. <!-- 数据源的个数 -->
  5. <property name="dscount" value="1" />
  6. <!-- dbGroupKeys 必填 -->
  7. <!-- 如果在末尾插入"-OFF",该源将被关掉,该源占据的SQL段会被保留" -->
  8. <!-- 当dbGroupKeys中配置的个数小于dbcount的值的时候,默认配置了"-OFF"的源 -->
  9. <property name="dbGroupKeys">
  10. <list>
  11. <value>CUNTAO_SUPPLIER_BODY00_GROUP</value>
  12. </list>
  13. </property>
  14. <!-- 内步长 ,默认为1000,取值在1-100000之间 -->
  15. <property name="innerStep" value="500" />
  16. <!-- 重试次数,在多个groupDataSource的场景下,建议设置成1-2次。默认为2次 -->
  17. <property name="retryTimes" value="2" />
  18. <!-- sequence表的表名 -->
  19. <property name="tableName" value="cuntao_supplier_sequence" />
  20. <!-- 自适应开关 ,默认为false -->
  21. <property name="adjust" value="true" />
  22. </bean>

TDDL分库分表配置bean

tddl-rule.xml

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <beans
  3. xmlns="http://www.springframework.org/schema/beans"
  4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5. xmlns:aop="http://www.springframework.org/schema/aop"
  6. xmlns:tx="http://www.springframework.org/schema/tx"
  7. xsi:schemaLocation="
  8. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
  9. http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
  10. http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
  11. <bean id="vtabroot" class="com.taobao.tddl.interact.rule.VirtualTableRoot" init-method="init">
  12. <property name="defaultDbIndex" value="CUNTAO_SUPPLIER_GROUP"/>
  13. <property name="dbType" value="MYSQL"/>
  14. <property name="tableRules">
  15. <map>
  16. <entry key="cuntao_purchase_order" value-ref="cuntao_purchase_order_bean"/>
  17. <entry key="cuntao_sub_purchase_order" value-ref="cuntao_sub_purchase_order_bean"/>
  18. <entry key="cuntao_logistics_order" value-ref="cuntao_logistics_order_bean"/>
  19. <entry key="cuntao_sub_logistics_order" value-ref="cuntao_sub_logistics_order_bean"/>
  20. </map>
  21. </property>
  22. </bean>
  23. <bean id="cuntao_purchase_order_bean" class="com.taobao.tddl.interact.rule.TableRule">
  24. <property name="dbNamePattern" value="CUNTAO_SUPPLIER_BODY{00}_GROUP"/>
  25. <property name="dbRuleArray">
  26. <value>(#supplier_id,1,256#.longValue() % 10000 % 256).intdiv(32)</value>
  27. </property>
  28. <property name="tbNamePattern" value="cuntao_purchase_order_{0000}" />
  29. <property name="tbRuleArray">
  30. <value>#supplier_id,1,256#.longValue() % 10000 % 256</value>
  31. </property>
  32. </bean>
  33. </beans>

  

配置项说明
分表总配置VirtualTableRoot:
其中,defaultDbIndex是appgroup,从DBA获取;dbType,数据库类型;tableRules引入各个表的配置

分库分表配置TableRule;其中,dbNamePattern分库规则,大括号会替换成dbRuleArray中的值.
dbRuleArray,分库计算方法,(#supplier_id,1,256#.longValue() % 10000 % 256).intdiv(32)表示以supplier_id为分表键,256张表,8个库所以除以32,我们计算规则取后四位计算所以先模10000.

tbNamePattern分表规则,大括号会替换成tbRuleArray中的值。
dbRuleArray,分表计算方法,#supplier_id,1,256#.longValue() % 10000 % 256 就是分库计算方法不除以32.

sequence生成bean
我们用的sequence是一个单库单表的数据库,即每次使用GroupSequence获取新的seq值来计算id,保证全局各个表不会发生id冲突。

appName,从DBA获得。

dbGroupKeys,所在库名称

tableName,sequence表名,可以使用一个sequence表来计算多个表的id,因为每个表实际只占用一行数据。

name,目标表在sequence表中的key,一般取表名,其实是任意的。

  • DefaultSequenceDao源码
  1. public class DefaultSequenceDao implements SequenceDao
  2. {
  3. private static final Log log = LogFactory.getLog(DefaultSequenceDao.class);
  4. private static final int MIN_STEP = 1;
  5. private static final int MAX_STEP = 100000;
  6. private static final int DEFAULT_STEP = 1000;
  7. private static final int DEFAULT_RETRY_TIMES = 150;
  8. private static final String DEFAULT_TABLE_NAME = "sequence";
  9. private static final String DEFAULT_NAME_COLUMN_NAME = "name";
  10. private static final String DEFAULT_VALUE_COLUMN_NAME = "value";
  11. private static final String DEFAULT_GMT_MODIFIED_COLUMN_NAME = "gmt_modified";
  12. private static final long DELTA = 100000000L;
  13. private DataSource dataSource;
  14. private int retryTimes = 150;
  15. private int step = 1000;
  16. private String tableName = "sequence";
  17. private String nameColumnName = "name";
  18. private String valueColumnName = "value";
  19. private String gmtModifiedColumnName = "gmt_modified";
  20. private volatile String selectSql;
  21. private volatile String updateSql;
  22.  
  23. public SequenceRange nextRange(String name)
  24. throws SequenceException
  25. {
  26. if (name == null) {
  27. throw new IllegalArgumentException("序列名称不能为空");
  28. }
  29.  
  30. Connection conn = null;
  31. PreparedStatement stmt = null;
  32. ResultSet rs = null;
  33.  
  34. for (int i = 0; i < this.retryTimes + 1; i++) { long oldValue;
  35. long newValue;
  36. try { conn = this.dataSource.getConnection();
  37. stmt = conn.prepareStatement(getSelectSql());
  38. stmt.setString(1, name);
  39. rs = stmt.executeQuery();
  40. rs.next();
  41. oldValue = rs.getLong(1);
  42.  
  43. if (oldValue < 0L) {
  44. StringBuilder message = new StringBuilder();
  45. message.append("Sequence value cannot be less than zero, value = ").append(oldValue);
  46. message.append(", please check table ").append(getTableName());
  47.  
  48. throw new SequenceException(message.toString());
  49. }
  50.  
  51. if (oldValue > 9223372036754775807L) {
  52. StringBuilder message = new StringBuilder();
  53. message.append("Sequence value overflow, value = ").append(oldValue);
  54. message.append(", please check table ").append(getTableName());
  55.  
  56. throw new SequenceException(message.toString());
  57. }
  58.  
  59. newValue = oldValue + getStep();
  60. } catch (SQLException e) {
  61. throw new SequenceException(e);
  62. } finally {
  63. closeResultSet(rs);
  64. rs = null;
  65. closeStatement(stmt);
  66. stmt = null;
  67. closeConnection(conn);
  68. conn = null;
  69. }
  70. try
  71. {
  72. conn = this.dataSource.getConnection();
  73. stmt = conn.prepareStatement(getUpdateSql());
  74. stmt.setLong(1, newValue);
  75. stmt.setTimestamp(2, new Timestamp(System.currentTimeMillis()));
  76. stmt.setString(3, name);
  77. stmt.setLong(4, oldValue);
  78. int affectedRows = stmt.executeUpdate();
  79. if (affectedRows == 0)
  80. {
  81. closeStatement(stmt);
  82. stmt = null;
  83. closeConnection(conn);
  84. conn = null;
  85. }
  86. else
  87. {
  88. return new SequenceRange(oldValue + 1L, newValue);
  89. }
  90. } catch (SQLException e) { throw new SequenceException(e);
  91. } finally {
  92. closeStatement(stmt);
  93. stmt = null;
  94. closeConnection(conn);
  95. conn = null;
  96. }
  97. }
  98.  
  99. throw new SequenceException("Retried too many times, retryTimes = " + this.retryTimes);
  100. }
  101.  
  102. private String getSelectSql() {
  103. if (this.selectSql == null) {
  104. synchronized (this) {
  105. if (this.selectSql == null) {
  106. StringBuilder buffer = new StringBuilder();
  107. buffer.append("select ").append(getValueColumnName());
  108. buffer.append(" from ").append(getTableName());
  109. buffer.append(" where ").append(getNameColumnName()).append(" = ?");
  110.  
  111. this.selectSql = buffer.toString();
  112. }
  113. }
  114. }
  115.  
  116. return this.selectSql;
  117. }
  118.  
  119. private String getUpdateSql() {
  120. if (this.updateSql == null) {
  121. synchronized (this) {
  122. if (this.updateSql == null) {
  123. StringBuilder buffer = new StringBuilder();
  124. buffer.append("update ").append(getTableName());
  125. buffer.append(" set ").append(getValueColumnName()).append(" = ?, ");
  126. buffer.append(getGmtModifiedColumnName()).append(" = ? where ");
  127. buffer.append(getNameColumnName()).append(" = ? and ");
  128. buffer.append(getValueColumnName()).append(" = ?");
  129.  
  130. this.updateSql = buffer.toString();
  131. }
  132. }
  133. }
  134.  
  135. return this.updateSql;
  136. }
  137.  
  138. private static void closeResultSet(ResultSet rs) {
  139. if (rs != null)
  140. try {
  141. rs.close();
  142. } catch (SQLException e) {
  143. log.debug("Could not close JDBC ResultSet", e);
  144. } catch (Throwable e) {
  145. log.debug("Unexpected exception on closing JDBC ResultSet", e);
  146. }
  147. }
  148.  
  149. private static void closeStatement(Statement stmt)
  150. {
  151. if (stmt != null)
  152. try {
  153. stmt.close();
  154. } catch (SQLException e) {
  155. log.debug("Could not close JDBC Statement", e);
  156. } catch (Throwable e) {
  157. log.debug("Unexpected exception on closing JDBC Statement", e);
  158. }
  159. }
  160.  
  161. private static void closeConnection(Connection conn)
  162. {
  163. if (conn != null)
  164. try {
  165. conn.close();
  166. } catch (SQLException e) {
  167. log.debug("Could not close JDBC Connection", e);
  168. } catch (Throwable e) {
  169. log.debug("Unexpected exception on closing JDBC Connection", e);
  170. }
  171. }
  172.  
  173. ...
  • GroupSequenceDao源码
  1. public class GroupSequenceDao implements SequenceDao
  2. {
  3. private static final Log log = LogFactory.getLog(GroupSequenceDao.class);
  4. private static final int MIN_STEP = 1;
  5. private static final int MAX_STEP = 100000;
  6. private static final int DEFAULT_INNER_STEP = 1000;
  7. private static final int DEFAULT_RETRY_TIMES = 2;
  8. private static final String DEFAULT_TABLE_NAME = "sequence";
  9. private static final String DEFAULT_NAME_COLUMN_NAME = "name";
  10. private static final String DEFAULT_VALUE_COLUMN_NAME = "value";
  11. private static final String DEFAULT_GMT_MODIFIED_COLUMN_NAME = "gmt_modified";
  12. private static final int DEFAULT_DSCOUNT = 2;
  13. private static final Boolean DEFAULT_ADJUST = Boolean.valueOf(false);
  14. private static final long DELTA = 100000000L;
  15. private String appName;
  16. private List<String> dbGroupKeys;
  17. private Map<String, DataSource> dataSourceMap;
  18. private boolean adjust = DEFAULT_ADJUST.booleanValue();
  19.  
  20. private int retryTimes = 2;
  21. private int dscount = 2;
  22. private int innerStep = 1000;
  23. private int outStep = 1000;
  24. private String tableName = "sequence";
  25. private String nameColumnName = "name";
  26. private String valueColumnName = "value";
  27. private String gmtModifiedColumnName = "gmt_modified";
  28. private volatile String selectSql;
  29. private volatile String updateSql;
  30. private volatile String insertSql;
  31. private ConcurrentHashMap<Integer, AtomicInteger> excludedKeyCount = new ConcurrentHashMap(this.dscount);
  32. private int maxSkipCount = 10000;
  33. private boolean useSlowProtect = false;
  34. private int protectMilliseconds = 50;
  35. private ExecutorService exec = Executors.newFixedThreadPool(1);
  36.  
  37. public void init()
  38. throws SequenceException
  39. {
  40. if (StringUtils.isEmpty(this.appName)) {
  41. SequenceException sequenceException = new SequenceException("appName is Null ");
  42.  
  43. log.error("没有配置appName", sequenceException);
  44. throw sequenceException;
  45. }
  46. if ((this.dbGroupKeys == null) || (this.dbGroupKeys.size() == 0)) {
  47. log.error("没有配置dbgroupKeys");
  48. throw new SequenceException("dbgroupKeys为空!");
  49. }
  50.  
  51. this.dataSourceMap = new HashMap();
  52. for (String dbGroupKey : this.dbGroupKeys)
  53. if (!dbGroupKey.toUpperCase().endsWith("-OFF"))
  54. {
  55. TGroupDataSource tGroupDataSource = new TGroupDataSource(dbGroupKey, this.appName);
  56.  
  57. tGroupDataSource.init();
  58. this.dataSourceMap.put(dbGroupKey, tGroupDataSource);
  59. }
  60. if (this.dbGroupKeys.size() >= this.dscount)
  61. this.dscount = this.dbGroupKeys.size();
  62. else {
  63. for (int ii = this.dbGroupKeys.size(); ii < this.dscount; ii++) {
  64. this.dbGroupKeys.add(new StringBuilder().append(this.dscount).append("-OFF").toString());
  65. }
  66. }
  67. this.outStep = (this.innerStep * this.dscount);
  68.  
  69. StringBuilder sb = new StringBuilder();
  70. sb.append("GroupSequenceDao初始化完成:\r\n ");
  71. sb.append("appName:").append(this.appName).append("\r\n");
  72. sb.append("innerStep:").append(this.innerStep).append("\r\n");
  73. sb.append("dataSource:").append(this.dscount).append("个:");
  74. for (String str : this.dbGroupKeys) {
  75. sb.append("[").append(str).append("]、");
  76. }
  77. sb.append("\r\n");
  78. sb.append("adjust:").append(this.adjust).append("\r\n");
  79. sb.append("retryTimes:").append(this.retryTimes).append("\r\n");
  80. sb.append("tableName:").append(this.tableName).append("\r\n");
  81. sb.append("nameColumnName:").append(this.nameColumnName).append("\r\n");
  82. sb.append("valueColumnName:").append(this.valueColumnName).append("\r\n");
  83. sb.append("gmtModifiedColumnName:").append(this.gmtModifiedColumnName).append("\r\n");
  84.  
  85. log.info(sb.toString());
  86. }
  87.  
  88. private boolean check(int index, long value)
  89. {
  90. return value % this.outStep == index * this.innerStep;
  91. }
  92.  
  93. public void adjust(String name)
  94. throws SequenceException, SQLException
  95. {
  96. Connection conn = null;
  97. PreparedStatement stmt = null;
  98. ResultSet rs = null;
  99.  
  100. for (int i = 0; i < this.dbGroupKeys.size(); i++)
  101. if (!((String)this.dbGroupKeys.get(i)).toUpperCase().endsWith("-OFF"))
  102. {
  103. TGroupDataSource tGroupDataSource = (TGroupDataSource)this.dataSourceMap.get(this.dbGroupKeys.get(i));
  104. try
  105. {
  106. conn = tGroupDataSource.getConnection();
  107. stmt = conn.prepareStatement(getSelectSql());
  108. stmt.setString(1, name);
  109. GroupDataSourceRouteHelper.executeByGroupDataSourceIndex(0);
  110. rs = stmt.executeQuery();
  111. int item = 0;
  112. while (rs.next()) {
  113. item++;
  114. long val = rs.getLong(getValueColumnName());
  115. if (!check(i, val))
  116. {
  117. if (isAdjust()) {
  118. adjustUpdate(i, val, name);
  119. } else {
  120. log.error("数据库中配置的初值出错!请调整你的数据库,或者启动adjust开关");
  121. throw new SequenceException("数据库中配置的初值出错!请调整你的数据库,或者启动adjust开关");
  122. }
  123. }
  124. }
  125.  
  126. if (item == 0)
  127. {
  128. if (isAdjust()) {
  129. adjustInsert(i, name);
  130. } else {
  131. log.error("数据库中未配置该sequence!请往数据库中插入sequence记录,或者启动adjust开关");
  132. throw new SequenceException("数据库中未配置该sequence!请往数据库中插入sequence记录,或者启动adjust开关");
  133. }
  134. }
  135. }
  136. catch (SQLException e) {
  137. log.error("初值校验和自适应过程中出错.", e);
  138. throw e;
  139. } finally {
  140. closeResultSet(rs);
  141. rs = null;
  142. closeStatement(stmt);
  143. stmt = null;
  144. closeConnection(conn);
  145. conn = null;
  146. }
  147. }
  148. }
  149.  
  150. private void adjustUpdate(int index, long value, String name)
  151. throws SequenceException, SQLException
  152. {
  153. long newValue = value - value % this.outStep + this.outStep + index * this.innerStep;
  154. TGroupDataSource tGroupDataSource = (TGroupDataSource)this.dataSourceMap.get(this.dbGroupKeys.get(index));
  155.  
  156. Connection conn = null;
  157. PreparedStatement stmt = null;
  158. ResultSet rs = null;
  159. try {
  160. conn = tGroupDataSource.getConnection();
  161. stmt = conn.prepareStatement(getUpdateSql());
  162. stmt.setLong(1, newValue);
  163. stmt.setTimestamp(2, new Timestamp(System.currentTimeMillis()));
  164. stmt.setString(3, name);
  165. stmt.setLong(4, value);
  166. GroupDataSourceRouteHelper.executeByGroupDataSourceIndex(0);
  167. int affectedRows = stmt.executeUpdate();
  168. if (affectedRows == 0) {
  169. throw new SequenceException(new StringBuilder().append("faild to auto adjust init value at ").append(name).append(" update affectedRow =0").toString());
  170. }
  171.  
  172. log.info(new StringBuilder().append((String)this.dbGroupKeys.get(index)).append("更新初值成功!").append("sequence Name:").append(name).append("更新过程:").append(value).append("-->").append(newValue).toString());
  173. }
  174. catch (SQLException e) {
  175. log.error(new StringBuilder().append("由于SQLException,更新初值自适应失败!dbGroupIndex:").append((String)this.dbGroupKeys.get(index)).append(",sequence Name:").append(name).append("更新过程:").append(value).append("-->").append(newValue).toString(), e);
  176.  
  177. throw new SequenceException(new StringBuilder().append("由于SQLException,更新初值自适应失败!dbGroupIndex:").append((String)this.dbGroupKeys.get(index)).append(",sequence Name:").append(name).append("更新过程:").append(value).append("-->").append(newValue).toString(), e);
  178. }
  179. finally
  180. {
  181. closeStatement(stmt);
  182. stmt = null;
  183. closeConnection(conn);
  184. conn = null;
  185. }
  186. }
  187.  
  188. private void adjustInsert(int index, String name)
  189. throws SequenceException, SQLException
  190. {
  191. TGroupDataSource tGroupDataSource = (TGroupDataSource)this.dataSourceMap.get(this.dbGroupKeys.get(index));
  192.  
  193. long newValue = index * this.innerStep;
  194. Connection conn = null;
  195. PreparedStatement stmt = null;
  196. ResultSet rs = null;
  197. try {
  198. conn = tGroupDataSource.getConnection();
  199. stmt = conn.prepareStatement(getInsertSql());
  200. stmt.setString(1, name);
  201. stmt.setLong(2, newValue);
  202. stmt.setTimestamp(3, new Timestamp(System.currentTimeMillis()));
  203. GroupDataSourceRouteHelper.executeByGroupDataSourceIndex(0);
  204. int affectedRows = stmt.executeUpdate();
  205. if (affectedRows == 0) {
  206. throw new SequenceException(new StringBuilder().append("faild to auto adjust init value at ").append(name).append(" update affectedRow =0").toString());
  207. }
  208.  
  209. log.info(new StringBuilder().append((String)this.dbGroupKeys.get(index)).append(" name:").append(name).append("插入初值:").append(name).append("value:").append(newValue).toString());
  210. }
  211. catch (SQLException e)
  212. {
  213. log.error(new StringBuilder().append("由于SQLException,插入初值自适应失败!dbGroupIndex:").append((String)this.dbGroupKeys.get(index)).append(",sequence Name:").append(name).append(" value:").append(newValue).toString(), e);
  214.  
  215. throw new SequenceException(new StringBuilder().append("由于SQLException,插入初值自适应失败!dbGroupIndex:").append((String)this.dbGroupKeys.get(index)).append(",sequence Name:").append(name).append(" value:").append(newValue).toString(), e);
  216. }
  217. finally
  218. {
  219. closeResultSet(rs);
  220. rs = null;
  221. closeStatement(stmt);
  222. stmt = null;
  223. closeConnection(conn);
  224. conn = null;
  225. }
  226. }
  227.  
  228. public SequenceRange nextRange(final String name)
  229. throws SequenceException
  230. {
  231. if (name == null) {
  232. log.error("序列名为空!");
  233. throw new IllegalArgumentException("序列名称不能为空");
  234. }
  235.  
  236. Connection conn = null;
  237. PreparedStatement stmt = null;
  238. ResultSet rs = null;
  239.  
  240. int[] randomIntSequence = RandomSequence.randomIntSequence(this.dscount);
  241. for (int i = 0; i < this.retryTimes; i++) {
  242. for (int j = 0; j < this.dscount; j++) {
  243. boolean readSuccess = false;
  244. boolean writeSuccess = false;
  245. int index = randomIntSequence[j];
  246. if (!((String)this.dbGroupKeys.get(index)).toUpperCase().endsWith("-OFF"))
  247. {
  248. if (this.excludedKeyCount.get(Integer.valueOf(index)) != null) {
  249. if (((AtomicInteger)this.excludedKeyCount.get(Integer.valueOf(index))).incrementAndGet() > this.maxSkipCount) {
  250. this.excludedKeyCount.remove(Integer.valueOf(index));
  251. log.error(new StringBuilder().append(this.maxSkipCount).append("次数已过,index为").append(index).append("的数据源后续重新尝试取序列").toString());
  252. }
  253.  
  254. }
  255. else
  256. {
  257. final TGroupDataSource tGroupDataSource = (TGroupDataSource)this.dataSourceMap.get(this.dbGroupKeys.get(index));
  258. long oldValue;
  259. long newValue;
  260. try
  261. {
  262. long oldValue;
  263. if ((!this.useSlowProtect) || (this.excludedKeyCount.size() >= this.dscount - 1)) {
  264. conn = tGroupDataSource.getConnection();
  265. stmt = conn.prepareStatement(getSelectSql());
  266. stmt.setString(1, name);
  267. GroupDataSourceRouteHelper.executeByGroupDataSourceIndex(0);
  268. rs = stmt.executeQuery();
  269. rs.next();
  270. oldValue = rs.getLong(1);
  271. } else {
  272. FutureTask future = new FutureTask(new Callable()
  273. {
  274. public Long call() throws Exception
  275. {
  276. Connection fconn = null;
  277. PreparedStatement fstmt = null;
  278. ResultSet frs = null;
  279. try {
  280. fconn = tGroupDataSource.getConnection();
  281. fstmt = fconn.prepareStatement(GroupSequenceDao.this.getSelectSql());
  282. fstmt.setString(1, name);
  283. GroupDataSourceRouteHelper.executeByGroupDataSourceIndex(0);
  284. frs = fstmt.executeQuery();
  285. frs.next();
  286. return Long.valueOf(frs.getLong(1));
  287. } finally {
  288. GroupSequenceDao.closeResultSet(frs);
  289. frs = null;
  290. GroupSequenceDao.closeStatement(fstmt);
  291. fstmt = null;
  292. GroupSequenceDao.closeConnection(fconn);
  293. fconn = null;
  294. }
  295. }
  296. });
  297. try
  298. {
  299. this.exec.submit(future);
  300. oldValue = ((Long)future.get(this.protectMilliseconds, TimeUnit.MILLISECONDS)).longValue();
  301. } catch (InterruptedException e) {
  302. throw new SQLException("[SEQUENCE SLOW-PROTECTED MODE]:InterruptedException", e);
  303. } catch (ExecutionException e) {
  304. throw new SQLException("[SEQUENCE SLOW-PROTECTED MODE]:ExecutionException", e);
  305. } catch (TimeoutException e) {
  306. throw new SQLException(new StringBuilder().append("[SEQUENCE SLOW-PROTECTED MODE]:TimeoutException,当前设置超时时间为").append(this.protectMilliseconds).toString(), e);
  307. }
  308. }
  309.  
  310. if (oldValue < 0L) {
  311. StringBuilder message = new StringBuilder();
  312. message.append("Sequence value cannot be less than zero, value = ").append(oldValue);
  313.  
  314. message.append(", please check table ").append(getTableName());
  315.  
  316. log.info(message);
  317.  
  318. closeResultSet(rs);
  319. rs = null;
  320. closeStatement(stmt);
  321. stmt = null;
  322. closeConnection(conn);
  323. conn = null; continue;
  324. }
  325. if (oldValue > 9223372036754775807L) {
  326. StringBuilder message = new StringBuilder();
  327. message.append("Sequence value overflow, value = ").append(oldValue);
  328.  
  329. message.append(", please check table ").append(getTableName());
  330.  
  331. log.info(message);
  332.  
  333. closeResultSet(rs);
  334. rs = null;
  335. closeStatement(stmt);
  336. stmt = null;
  337. closeConnection(conn);
  338. conn = null; continue;
  339. }
  340. newValue = oldValue + this.outStep;
  341. if (!check(index, newValue))
  342. {
  343. if (isAdjust()) {
  344. newValue = newValue - newValue % this.outStep + this.outStep + index * this.innerStep;
  345. }
  346. else {
  347. SequenceException sequenceException = new SequenceException(new StringBuilder().append((String)this.dbGroupKeys.get(index)).append(":").append(name).append("的值得错误,覆盖到其他范围段了!请修改数据库,或者开启adjust开关!").toString());
  348.  
  349. log.error(new StringBuilder().append((String)this.dbGroupKeys.get(index)).append(":").append(name).append("的值得错误,覆盖到其他范围段了!请修改数据库,或者开启adjust开关!").toString(), sequenceException);
  350.  
  351. throw sequenceException;
  352. }
  353.  
  354. }
  355.  
  356. closeResultSet(rs);
  357. rs = null;
  358. closeStatement(stmt);
  359. stmt = null;
  360. closeConnection(conn);
  361. conn = null;
  362. }
  363. catch (SQLException e)
  364. {
  365. log.error(new StringBuilder().append("取范围过程中--查询出错!").append((String)this.dbGroupKeys.get(index)).append(":").append(name).toString(), e);
  366.  
  367. if (this.excludedKeyCount.size() < this.dscount - 1) {
  368. this.excludedKeyCount.put(Integer.valueOf(index), new AtomicInteger(0));
  369. log.error(new StringBuilder().append("暂时踢除index为").append(index).append("的数据源,").append(this.maxSkipCount).append("次后重新尝试").toString());
  370. }
  371. }
  372. finally
  373. {
  374. closeResultSet(rs);
  375. rs = null;
  376. closeStatement(stmt);
  377. stmt = null;
  378. closeConnection(conn);
  379. conn = null;
  380. }
  381.  
  382. try
  383. {
  384. conn = tGroupDataSource.getConnection();
  385. stmt = conn.prepareStatement(getUpdateSql());
  386. stmt.setLong(1, newValue);
  387. stmt.setTimestamp(2, new Timestamp(System.currentTimeMillis()));
  388.  
  389. stmt.setString(3, name);
  390. stmt.setLong(4, oldValue);
  391. GroupDataSourceRouteHelper.executeByGroupDataSourceIndex(0);
  392. int affectedRows = stmt.executeUpdate();
  393. if (affectedRows == 0)
  394. {
  395. closeStatement(stmt);
  396. stmt = null;
  397. closeConnection(conn);
  398. conn = null;
  399. }
  400. else
  401. {
  402. closeStatement(stmt);
  403. stmt = null;
  404. closeConnection(conn);
  405. conn = null;
  406. }
  407. }
  408. catch (SQLException e)
  409. {
  410. log.error(new StringBuilder().append("取范围过程中--更新出错!").append((String)this.dbGroupKeys.get(index)).append(":").append(name).toString(), e);
  411. }
  412. finally
  413. {
  414. closeStatement(stmt);
  415. stmt = null;
  416. closeConnection(conn);
  417. conn = null;
  418. }
  419. }
  420. }
  421.  
  422. }
  423.  
  424. if (i == this.retryTimes - 2) {
  425. this.excludedKeyCount.clear();
  426. }
  427. }
  428. log.error(new StringBuilder().append("所有数据源都不可用!且重试").append(this.retryTimes).append("次后,仍然失败!").toString());
  429. throw new SequenceException("All dataSource faild to get value!");
  430. }
  431.  
  432. private String getInsertSql() {
  433. if (this.insertSql == null) {
  434. synchronized (this) {
  435. if (this.insertSql == null) {
  436. StringBuilder buffer = new StringBuilder();
  437. buffer.append("insert into ").append(getTableName()).append("(");
  438.  
  439. buffer.append(getNameColumnName()).append(",");
  440. buffer.append(getValueColumnName()).append(",");
  441. buffer.append(getGmtModifiedColumnName()).append(") values(?,?,?);");
  442.  
  443. this.insertSql = buffer.toString();
  444. }
  445. }
  446. }
  447. return this.insertSql;
  448. }
  449.  
  450. private String getSelectSql() {
  451. if (this.selectSql == null) {
  452. synchronized (this) {
  453. if (this.selectSql == null) {
  454. StringBuilder buffer = new StringBuilder();
  455. buffer.append("select ").append(getValueColumnName());
  456. buffer.append(" from ").append(getTableName());
  457. buffer.append(" where ").append(getNameColumnName()).append(" = ?");
  458.  
  459. this.selectSql = buffer.toString();
  460. }
  461. }
  462. }
  463.  
  464. return this.selectSql;
  465. }
  466.  
  467. private String getUpdateSql() {
  468. if (this.updateSql == null) {
  469. synchronized (this) {
  470. if (this.updateSql == null) {
  471. StringBuilder buffer = new StringBuilder();
  472. buffer.append("update ").append(getTableName());
  473. buffer.append(" set ").append(getValueColumnName()).append(" = ?, ");
  474.  
  475. buffer.append(getGmtModifiedColumnName()).append(" = ? where ");
  476.  
  477. buffer.append(getNameColumnName()).append(" = ? and ");
  478. buffer.append(getValueColumnName()).append(" = ?");
  479.  
  480. this.updateSql = buffer.toString();
  481. }
  482. }
  483. }
  484.  
  485. return this.updateSql;
  486. }
  487.  
  488. private static void closeResultSet(ResultSet rs) {
  489. if (rs != null)
  490. try {
  491. rs.close();
  492. } catch (SQLException e) {
  493. log.debug("Could not close JDBC ResultSet", e);
  494. } catch (Throwable e) {
  495. log.debug("Unexpected exception on closing JDBC ResultSet", e);
  496. }
  497. }
  498.  
  499. private static void closeStatement(Statement stmt)
  500. {
  501. if (stmt != null)
  502. try {
  503. stmt.close();
  504. } catch (SQLException e) {
  505. log.debug("Could not close JDBC Statement", e);
  506. } catch (Throwable e) {
  507. log.debug("Unexpected exception on closing JDBC Statement", e);
  508. }
  509. }
  510.  
  511. private static void closeConnection(Connection conn)
  512. {
  513. if (conn != null)
  514. try {
  515. conn.close();
  516. } catch (SQLException e) {
  517. log.debug("Could not close JDBC Connection", e);
  518. } catch (Throwable e) {
  519. log.debug("Unexpected exception on closing JDBC Connection", e);
  520. }
  521. }

TDDL实践的更多相关文章

  1. mongodb 最佳实践

    MongoDB功能预览:http://pan.baidu.com/s/1k2UfW MongoDB在赶集网的应用:http://pan.baidu.com/s/1bngxgLp MongoDB在京东的 ...

  2. 【大数据和云计算技术社区】分库分表技术演进&最佳实践笔记

    1.需求背景 移动互联网时代,海量的用户每天产生海量的数量,这些海量数据远不是一张表能Hold住的.比如 用户表:支付宝8亿,微信10亿.CITIC对公140万,对私8700万. 订单表:美团每天几千 ...

  3. TDDL调研笔记

    一,TDDL是什么 Taobao Distributed Data Layer,即淘宝分布式数据层,简称TDDL .它是一套分布式数据访问引擎 淘宝一个基于客户端的数据库中间件产品 基于JDBC规范, ...

  4. 分库分表技术演进&最佳实践

    每个优秀的程序员和架构师都应该掌握分库分表,这是我的观点. 移动互联网时代,海量的用户每天产生海量的数量,比如: 用户表 订单表 交易流水表 以支付宝用户为例,8亿:微信用户更是10亿.订单表更夸张, ...

  5. webp图片实践之路

    最近,我们在项目中实践了webp图片,并且抽离出了工具模块,整合到了项目的基础模板中.传闻IOS10也将要支持webp,那么使用webp带来的性能提升将更加明显.估计在不久的将来,webp会成为标配. ...

  6. Hangfire项目实践分享

    Hangfire项目实践分享 目录 Hangfire项目实践分享 目录 什么是Hangfire Hangfire基础 基于队列的任务处理(Fire-and-forget jobs) 延迟任务执行(De ...

  7. TDD在Unity3D游戏项目开发中的实践

    0x00 前言 关于TDD测试驱动开发的文章已经有很多了,但是在游戏开发尤其是使用Unity3D开发游戏时,却听不到特别多关于TDD的声音.那么本文就来简单聊一聊TDD如何在U3D项目中使用以及如何使 ...

  8. Logstash实践: 分布式系统的日志监控

    文/赵杰 2015.11.04 1. 前言 服务端日志你有多重视? 我们没有日志 有日志,但基本不去控制需要输出的内容 经常微调日志,只输出我们想看和有用的 经常监控日志,一方面帮助日志微调,一方面及 ...

  9. 【大型网站技术实践】初级篇:借助Nginx搭建反向代理服务器

    一.反向代理:Web服务器的“经纪人” 1.1 反向代理初印象 反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从 ...

随机推荐

  1. UART学习之路(一)基本概念

    第一篇博客,首先记录一下这一个多星期来的学习内容. UART学习之路第一篇,是UART的基本概念介绍.后续会用STM32F103的串口与PC机通信.最后使用Verilog HDL写出串口发送模块和接收 ...

  2. Win10系统下VirtualBox虚拟机初体验

    在接触本次的VirtualBox之前,我在大一下学期参加李冬冬老师的选修课中学习过VMware,并使用VMware进行过一些计算机病毒之类的实验.但是,使用虚拟机模拟其他不同操作系统这次是第一次,因此 ...

  3. 【CF908G】New Year and Original Order

    [CF908G]New Year and Original Order 题面 洛谷 题解 设\(f[i][j][k][l]\)表示当前在第\(i\)位有\(j\)位大于等于\(k\),当前有没有卡上界 ...

  4. git clone的时候报error: RPC failed; result=18错误

    因业务需求,需要把内网gitlab仓库的地址对外网访问,在gitlab前端配置了一个nginx代理服务器,来实现需求,可以在git clone的时候报error: RPC failed错误 [root ...

  5. crontab练习题

    Crontab练习题 每周一到周六的凌晨3点20分,运行tar命令对/etc/目录进行存档另存,存储位置为/backups/etc-YYYY-MM-DD.tar.gz 20 3 * * 1-6 /us ...

  6. unity图形圆形展开

    脚本如下: using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngi ...

  7. 用反射或委托优化switch太长的方法

    在代码进行优化的时候,发现了switch case太长,有的竟然长达30个远远超过一屏这样在代码的可读性来说很差.特别在我们看代码的时候要拉下拉框我个人觉得这是不合理的.但是我不建议有switch就进 ...

  8. WebGL中使用window.requestAnimationFrame创建主循环

    今天总结记录一下WebGL中主循环的创建和作用.我先说明什么是主循环,其实单纯的webgl不存在主循环这个概念,这个概念是由渲染引擎引入的,主循环就是利用一个死循环或无截止条件的递归达到定时刷新can ...

  9. application/x-www-urlencoded与multipart/form-data

    学习ajax时,学到了GET与POST两种HTTP方法,于是去W3C看了二者的区别,里面提到了二者的编码类型不同,就在网上查阅了相关资料, 在这里把我查阅到的相关结果记录在此,方便以后学习,详细了解一 ...

  10. Linux内核学习笔记(3)-- 进程的创建和终结

    一. 进程创建: Unix 下的进程创建很特别,与许多其他操作系统不同,它分两步操作来创建和执行进程: fork() 和 exec() .首先,fork() 通过拷贝当前进程创建一个子进程:然后,ex ...