TDDL实践

使用入门-数据源配置

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

myDataSource--分库分表数据源

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

appRuleFile--分库分表配置文件

useLocalConfig--使用本地配置

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

TDDL分库分表配置bean

tddl-rule.xml

<?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:aop="http://www.springframework.org/schema/aop"
    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.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
    <bean id="vtabroot" class="com.taobao.tddl.interact.rule.VirtualTableRoot" init-method="init">
        <property name="defaultDbIndex" value="CUNTAO_SUPPLIER_GROUP"/>
        <property name="dbType" value="MYSQL"/>
        <property name="tableRules">
            <map>
                <entry key="cuntao_purchase_order" value-ref="cuntao_purchase_order_bean"/>
                <entry key="cuntao_sub_purchase_order" value-ref="cuntao_sub_purchase_order_bean"/>
                <entry key="cuntao_logistics_order" value-ref="cuntao_logistics_order_bean"/>
                <entry key="cuntao_sub_logistics_order" value-ref="cuntao_sub_logistics_order_bean"/>
            </map>
        </property>
    </bean>
    <bean id="cuntao_purchase_order_bean" class="com.taobao.tddl.interact.rule.TableRule">
        <property name="dbNamePattern" value="CUNTAO_SUPPLIER_BODY{00}_GROUP"/>
        <property name="dbRuleArray">
            <value>(#supplier_id,1,256#.longValue() % 10000 % 256).intdiv(32)</value>
        </property>
        <property name="tbNamePattern" value="cuntao_purchase_order_{0000}" />
        <property name="tbRuleArray">
            <value>#supplier_id,1,256#.longValue() % 10000 % 256</value>
        </property>
    </bean>
</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源码
public class DefaultSequenceDao implements SequenceDao
{
  private static final Log log = LogFactory.getLog(DefaultSequenceDao.class);
  private static final int MIN_STEP = 1;
  private static final int MAX_STEP = 100000;
  private static final int DEFAULT_STEP = 1000;
  private static final int DEFAULT_RETRY_TIMES = 150;
  private static final String DEFAULT_TABLE_NAME = "sequence";
  private static final String DEFAULT_NAME_COLUMN_NAME = "name";
  private static final String DEFAULT_VALUE_COLUMN_NAME = "value";
  private static final String DEFAULT_GMT_MODIFIED_COLUMN_NAME = "gmt_modified";
  private static final long DELTA = 100000000L;
private DataSource dataSource; private int retryTimes = 150; private int step = 1000; private String tableName = "sequence"; private String nameColumnName = "name"; private String valueColumnName = "value"; private String gmtModifiedColumnName = "gmt_modified"; private volatile String selectSql; private volatile String updateSql; public SequenceRange nextRange(String name) throws SequenceException { if (name == null) { throw new IllegalArgumentException("序列名称不能为空"); } Connection conn = null; PreparedStatement stmt = null; ResultSet rs = null; for (int i = 0; i < this.retryTimes + 1; i++) { long oldValue; long newValue; try { conn = this.dataSource.getConnection(); stmt = conn.prepareStatement(getSelectSql()); stmt.setString(1, name); rs = stmt.executeQuery(); rs.next(); oldValue = rs.getLong(1); if (oldValue < 0L) { StringBuilder message = new StringBuilder(); message.append("Sequence value cannot be less than zero, value = ").append(oldValue); message.append(", please check table ").append(getTableName()); throw new SequenceException(message.toString()); } if (oldValue > 9223372036754775807L) { StringBuilder message = new StringBuilder(); message.append("Sequence value overflow, value = ").append(oldValue); message.append(", please check table ").append(getTableName()); throw new SequenceException(message.toString()); } newValue = oldValue + getStep(); } catch (SQLException e) { throw new SequenceException(e); } finally { closeResultSet(rs); rs = null; closeStatement(stmt); stmt = null; closeConnection(conn); conn = null; } try { conn = this.dataSource.getConnection(); stmt = conn.prepareStatement(getUpdateSql()); stmt.setLong(1, newValue); stmt.setTimestamp(2, new Timestamp(System.currentTimeMillis())); stmt.setString(3, name); stmt.setLong(4, oldValue); int affectedRows = stmt.executeUpdate(); if (affectedRows == 0) { closeStatement(stmt); stmt = null; closeConnection(conn); conn = null; } else { return new SequenceRange(oldValue + 1L, newValue); } } catch (SQLException e) { throw new SequenceException(e); } finally { closeStatement(stmt); stmt = null; closeConnection(conn); conn = null; } } throw new SequenceException("Retried too many times, retryTimes = " + this.retryTimes); } private String getSelectSql() { if (this.selectSql == null) { synchronized (this) { if (this.selectSql == null) { StringBuilder buffer = new StringBuilder(); buffer.append("select ").append(getValueColumnName()); buffer.append(" from ").append(getTableName()); buffer.append(" where ").append(getNameColumnName()).append(" = ?"); this.selectSql = buffer.toString(); } } } return this.selectSql; } private String getUpdateSql() { if (this.updateSql == null) { synchronized (this) { if (this.updateSql == null) { StringBuilder buffer = new StringBuilder(); buffer.append("update ").append(getTableName()); buffer.append(" set ").append(getValueColumnName()).append(" = ?, "); buffer.append(getGmtModifiedColumnName()).append(" = ? where "); buffer.append(getNameColumnName()).append(" = ? and "); buffer.append(getValueColumnName()).append(" = ?"); this.updateSql = buffer.toString(); } } } return this.updateSql; } private static void closeResultSet(ResultSet rs) { if (rs != null) try { rs.close(); } catch (SQLException e) { log.debug("Could not close JDBC ResultSet", e); } catch (Throwable e) { log.debug("Unexpected exception on closing JDBC ResultSet", e); } } private static void closeStatement(Statement stmt) { if (stmt != null) try { stmt.close(); } catch (SQLException e) { log.debug("Could not close JDBC Statement", e); } catch (Throwable e) { log.debug("Unexpected exception on closing JDBC Statement", e); } } private static void closeConnection(Connection conn) { if (conn != null) try { conn.close(); } catch (SQLException e) { log.debug("Could not close JDBC Connection", e); } catch (Throwable e) { log.debug("Unexpected exception on closing JDBC Connection", e); } } ...
  • GroupSequenceDao源码
public class GroupSequenceDao implements SequenceDao
{
  private static final Log log = LogFactory.getLog(GroupSequenceDao.class);
  private static final int MIN_STEP = 1;
  private static final int MAX_STEP = 100000;
  private static final int DEFAULT_INNER_STEP = 1000;
  private static final int DEFAULT_RETRY_TIMES = 2;
  private static final String DEFAULT_TABLE_NAME = "sequence";
  private static final String DEFAULT_NAME_COLUMN_NAME = "name";
  private static final String DEFAULT_VALUE_COLUMN_NAME = "value";
  private static final String DEFAULT_GMT_MODIFIED_COLUMN_NAME = "gmt_modified";
  private static final int DEFAULT_DSCOUNT = 2;
  private static final Boolean DEFAULT_ADJUST = Boolean.valueOf(false);
  private static final long DELTA = 100000000L;
  private String appName;
  private List<String> dbGroupKeys;
  private Map<String, DataSource> dataSourceMap;
  private boolean adjust = DEFAULT_ADJUST.booleanValue();

  private int retryTimes = 2;
  private int dscount = 2;
  private int innerStep = 1000;
  private int outStep = 1000;
  private String tableName = "sequence";
  private String nameColumnName = "name";
  private String valueColumnName = "value";
  private String gmtModifiedColumnName = "gmt_modified";
  private volatile String selectSql;
  private volatile String updateSql;
  private volatile String insertSql;
  private ConcurrentHashMap<Integer, AtomicInteger> excludedKeyCount = new ConcurrentHashMap(this.dscount);
  private int maxSkipCount = 10000;
  private boolean useSlowProtect = false;
  private int protectMilliseconds = 50;
  private ExecutorService exec = Executors.newFixedThreadPool(1);

  public void init()
    throws SequenceException
  {
    if (StringUtils.isEmpty(this.appName)) {
      SequenceException sequenceException = new SequenceException("appName is Null ");

      log.error("没有配置appName", sequenceException);
      throw sequenceException;
    }
    if ((this.dbGroupKeys == null) || (this.dbGroupKeys.size() == 0)) {
      log.error("没有配置dbgroupKeys");
      throw new SequenceException("dbgroupKeys为空!");
    }

    this.dataSourceMap = new HashMap();
    for (String dbGroupKey : this.dbGroupKeys)
      if (!dbGroupKey.toUpperCase().endsWith("-OFF"))
      {
        TGroupDataSource tGroupDataSource = new TGroupDataSource(dbGroupKey, this.appName);

        tGroupDataSource.init();
        this.dataSourceMap.put(dbGroupKey, tGroupDataSource);
      }
    if (this.dbGroupKeys.size() >= this.dscount)
      this.dscount = this.dbGroupKeys.size();
    else {
      for (int ii = this.dbGroupKeys.size(); ii < this.dscount; ii++) {
        this.dbGroupKeys.add(new StringBuilder().append(this.dscount).append("-OFF").toString());
      }
    }
    this.outStep = (this.innerStep * this.dscount);

    StringBuilder sb = new StringBuilder();
    sb.append("GroupSequenceDao初始化完成:
 ");
    sb.append("appName:").append(this.appName).append("
");
    sb.append("innerStep:").append(this.innerStep).append("
");
    sb.append("dataSource:").append(this.dscount).append("个:");
    for (String str : this.dbGroupKeys) {
      sb.append("[").append(str).append("]、");
    }
    sb.append("
");
    sb.append("adjust:").append(this.adjust).append("
");
    sb.append("retryTimes:").append(this.retryTimes).append("
");
    sb.append("tableName:").append(this.tableName).append("
");
    sb.append("nameColumnName:").append(this.nameColumnName).append("
");
    sb.append("valueColumnName:").append(this.valueColumnName).append("
");
    sb.append("gmtModifiedColumnName:").append(this.gmtModifiedColumnName).append("
");

    log.info(sb.toString());
  }

  private boolean check(int index, long value)
  {
    return value % this.outStep == index * this.innerStep;
  }

  public void adjust(String name)
    throws SequenceException, SQLException
  {
    Connection conn = null;
    PreparedStatement stmt = null;
    ResultSet rs = null;

    for (int i = 0; i < this.dbGroupKeys.size(); i++)
      if (!((String)this.dbGroupKeys.get(i)).toUpperCase().endsWith("-OFF"))
      {
        TGroupDataSource tGroupDataSource = (TGroupDataSource)this.dataSourceMap.get(this.dbGroupKeys.get(i));
        try
        {
          conn = tGroupDataSource.getConnection();
          stmt = conn.prepareStatement(getSelectSql());
          stmt.setString(1, name);
          GroupDataSourceRouteHelper.executeByGroupDataSourceIndex(0);
          rs = stmt.executeQuery();
          int item = 0;
          while (rs.next()) {
            item++;
            long val = rs.getLong(getValueColumnName());
            if (!check(i, val))
            {
              if (isAdjust()) {
                adjustUpdate(i, val, name);
              } else {
                log.error("数据库中配置的初值出错!请调整你的数据库,或者启动adjust开关");
                throw new SequenceException("数据库中配置的初值出错!请调整你的数据库,或者启动adjust开关");
              }
            }
          }

          if (item == 0)
          {
            if (isAdjust()) {
              adjustInsert(i, name);
            } else {
              log.error("数据库中未配置该sequence!请往数据库中插入sequence记录,或者启动adjust开关");
              throw new SequenceException("数据库中未配置该sequence!请往数据库中插入sequence记录,或者启动adjust开关");
            }
          }
        }
        catch (SQLException e) {
          log.error("初值校验和自适应过程中出错.", e);
          throw e;
        } finally {
          closeResultSet(rs);
          rs = null;
          closeStatement(stmt);
          stmt = null;
          closeConnection(conn);
          conn = null;
        }
      }
  }

  private void adjustUpdate(int index, long value, String name)
    throws SequenceException, SQLException
  {
    long newValue = value - value % this.outStep + this.outStep + index * this.innerStep;
    TGroupDataSource tGroupDataSource = (TGroupDataSource)this.dataSourceMap.get(this.dbGroupKeys.get(index));

    Connection conn = null;
    PreparedStatement stmt = null;
    ResultSet rs = null;
    try {
      conn = tGroupDataSource.getConnection();
      stmt = conn.prepareStatement(getUpdateSql());
      stmt.setLong(1, newValue);
      stmt.setTimestamp(2, new Timestamp(System.currentTimeMillis()));
      stmt.setString(3, name);
      stmt.setLong(4, value);
      GroupDataSourceRouteHelper.executeByGroupDataSourceIndex(0);
      int affectedRows = stmt.executeUpdate();
      if (affectedRows == 0) {
        throw new SequenceException(new StringBuilder().append("faild to auto adjust init value at  ").append(name).append(" update affectedRow =0").toString());
      }

      log.info(new StringBuilder().append((String)this.dbGroupKeys.get(index)).append("更新初值成功!").append("sequence Name:").append(name).append("更新过程:").append(value).append("-->").append(newValue).toString());
    }
    catch (SQLException e) {
      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);

      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);
    }
    finally
    {
      closeStatement(stmt);
      stmt = null;
      closeConnection(conn);
      conn = null;
    }
  }

  private void adjustInsert(int index, String name)
    throws SequenceException, SQLException
  {
    TGroupDataSource tGroupDataSource = (TGroupDataSource)this.dataSourceMap.get(this.dbGroupKeys.get(index));

    long newValue = index * this.innerStep;
    Connection conn = null;
    PreparedStatement stmt = null;
    ResultSet rs = null;
    try {
      conn = tGroupDataSource.getConnection();
      stmt = conn.prepareStatement(getInsertSql());
      stmt.setString(1, name);
      stmt.setLong(2, newValue);
      stmt.setTimestamp(3, new Timestamp(System.currentTimeMillis()));
      GroupDataSourceRouteHelper.executeByGroupDataSourceIndex(0);
      int affectedRows = stmt.executeUpdate();
      if (affectedRows == 0) {
        throw new SequenceException(new StringBuilder().append("faild to auto adjust init value at  ").append(name).append(" update affectedRow =0").toString());
      }

      log.info(new StringBuilder().append((String)this.dbGroupKeys.get(index)).append("   name:").append(name).append("插入初值:").append(name).append("value:").append(newValue).toString());
    }
    catch (SQLException e)
    {
      log.error(new StringBuilder().append("由于SQLException,插入初值自适应失败!dbGroupIndex:").append((String)this.dbGroupKeys.get(index)).append(",sequence Name:").append(name).append("   value:").append(newValue).toString(), e);

      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);
    }
    finally
    {
      closeResultSet(rs);
      rs = null;
      closeStatement(stmt);
      stmt = null;
      closeConnection(conn);
      conn = null;
    }
  }

  public SequenceRange nextRange(final String name)
    throws SequenceException
  {
    if (name == null) {
      log.error("序列名为空!");
      throw new IllegalArgumentException("序列名称不能为空");
    }

    Connection conn = null;
    PreparedStatement stmt = null;
    ResultSet rs = null;

    int[] randomIntSequence = RandomSequence.randomIntSequence(this.dscount);
    for (int i = 0; i < this.retryTimes; i++) {
      for (int j = 0; j < this.dscount; j++) {
        boolean readSuccess = false;
        boolean writeSuccess = false;
        int index = randomIntSequence[j];
        if (!((String)this.dbGroupKeys.get(index)).toUpperCase().endsWith("-OFF"))
        {
          if (this.excludedKeyCount.get(Integer.valueOf(index)) != null) {
            if (((AtomicInteger)this.excludedKeyCount.get(Integer.valueOf(index))).incrementAndGet() > this.maxSkipCount) {
              this.excludedKeyCount.remove(Integer.valueOf(index));
              log.error(new StringBuilder().append(this.maxSkipCount).append("次数已过,index为").append(index).append("的数据源后续重新尝试取序列").toString());
            }

          }
          else
          {
            final TGroupDataSource tGroupDataSource = (TGroupDataSource)this.dataSourceMap.get(this.dbGroupKeys.get(index));
            long oldValue;
            long newValue;
            try
            {
              long oldValue;
              if ((!this.useSlowProtect) || (this.excludedKeyCount.size() >= this.dscount - 1)) {
                conn = tGroupDataSource.getConnection();
                stmt = conn.prepareStatement(getSelectSql());
                stmt.setString(1, name);
                GroupDataSourceRouteHelper.executeByGroupDataSourceIndex(0);
                rs = stmt.executeQuery();
                rs.next();
                oldValue = rs.getLong(1);
              } else {
                FutureTask future = new FutureTask(new Callable()
                {
                  public Long call() throws Exception
                  {
                    Connection fconn = null;
                    PreparedStatement fstmt = null;
                    ResultSet frs = null;
                    try {
                      fconn = tGroupDataSource.getConnection();
                      fstmt = fconn.prepareStatement(GroupSequenceDao.this.getSelectSql());
                      fstmt.setString(1, name);
                      GroupDataSourceRouteHelper.executeByGroupDataSourceIndex(0);
                      frs = fstmt.executeQuery();
                      frs.next();
                      return Long.valueOf(frs.getLong(1));
                    } finally {
                      GroupSequenceDao.closeResultSet(frs);
                      frs = null;
                      GroupSequenceDao.closeStatement(fstmt);
                      fstmt = null;
                      GroupSequenceDao.closeConnection(fconn);
                      fconn = null;
                    }
                  }
                });
                try
                {
                  this.exec.submit(future);
                  oldValue = ((Long)future.get(this.protectMilliseconds, TimeUnit.MILLISECONDS)).longValue();
                } catch (InterruptedException e) {
                  throw new SQLException("[SEQUENCE SLOW-PROTECTED MODE]:InterruptedException", e);
                } catch (ExecutionException e) {
                  throw new SQLException("[SEQUENCE SLOW-PROTECTED MODE]:ExecutionException", e);
                } catch (TimeoutException e) {
                  throw new SQLException(new StringBuilder().append("[SEQUENCE SLOW-PROTECTED MODE]:TimeoutException,当前设置超时时间为").append(this.protectMilliseconds).toString(), e);
                }
              }

              if (oldValue < 0L) {
                StringBuilder message = new StringBuilder();
                message.append("Sequence value cannot be less than zero, value = ").append(oldValue);

                message.append(", please check table ").append(getTableName());

                log.info(message);

                closeResultSet(rs);
                rs = null;
                closeStatement(stmt);
                stmt = null;
                closeConnection(conn);
                conn = null; continue;
              }
              if (oldValue > 9223372036754775807L) {
                StringBuilder message = new StringBuilder();
                message.append("Sequence value overflow, value = ").append(oldValue);

                message.append(", please check table ").append(getTableName());

                log.info(message);

                closeResultSet(rs);
                rs = null;
                closeStatement(stmt);
                stmt = null;
                closeConnection(conn);
                conn = null; continue;
              }
              newValue = oldValue + this.outStep;
              if (!check(index, newValue))
              {
                if (isAdjust()) {
                  newValue = newValue - newValue % this.outStep + this.outStep + index * this.innerStep;
                }
                else {
                  SequenceException sequenceException = new SequenceException(new StringBuilder().append((String)this.dbGroupKeys.get(index)).append(":").append(name).append("的值得错误,覆盖到其他范围段了!请修改数据库,或者开启adjust开关!").toString());

                  log.error(new StringBuilder().append((String)this.dbGroupKeys.get(index)).append(":").append(name).append("的值得错误,覆盖到其他范围段了!请修改数据库,或者开启adjust开关!").toString(), sequenceException);

                  throw sequenceException;
                }

              }

              closeResultSet(rs);
              rs = null;
              closeStatement(stmt);
              stmt = null;
              closeConnection(conn);
              conn = null;
            }
            catch (SQLException e)
            {
              log.error(new StringBuilder().append("取范围过程中--查询出错!").append((String)this.dbGroupKeys.get(index)).append(":").append(name).toString(), e);

              if (this.excludedKeyCount.size() < this.dscount - 1) {
                this.excludedKeyCount.put(Integer.valueOf(index), new AtomicInteger(0));
                log.error(new StringBuilder().append("暂时踢除index为").append(index).append("的数据源,").append(this.maxSkipCount).append("次后重新尝试").toString());
              }
            }
            finally
            {
              closeResultSet(rs);
              rs = null;
              closeStatement(stmt);
              stmt = null;
              closeConnection(conn);
              conn = null;
            }

            try
            {
              conn = tGroupDataSource.getConnection();
              stmt = conn.prepareStatement(getUpdateSql());
              stmt.setLong(1, newValue);
              stmt.setTimestamp(2, new Timestamp(System.currentTimeMillis()));

              stmt.setString(3, name);
              stmt.setLong(4, oldValue);
              GroupDataSourceRouteHelper.executeByGroupDataSourceIndex(0);
              int affectedRows = stmt.executeUpdate();
              if (affectedRows == 0)
              {
                closeStatement(stmt);
                stmt = null;
                closeConnection(conn);
                conn = null;
              }
              else
              {
                closeStatement(stmt);
                stmt = null;
                closeConnection(conn);
                conn = null;
              }
            }
            catch (SQLException e)
            {
              log.error(new StringBuilder().append("取范围过程中--更新出错!").append((String)this.dbGroupKeys.get(index)).append(":").append(name).toString(), e);
            }
            finally
            {
              closeStatement(stmt);
              stmt = null;
              closeConnection(conn);
              conn = null;
            }
          }
        }

      }

      if (i == this.retryTimes - 2) {
        this.excludedKeyCount.clear();
      }
    }
    log.error(new StringBuilder().append("所有数据源都不可用!且重试").append(this.retryTimes).append("次后,仍然失败!").toString());
    throw new SequenceException("All dataSource faild to get value!");
  }

  private String getInsertSql() {
    if (this.insertSql == null) {
      synchronized (this) {
        if (this.insertSql == null) {
          StringBuilder buffer = new StringBuilder();
          buffer.append("insert into ").append(getTableName()).append("(");

          buffer.append(getNameColumnName()).append(",");
          buffer.append(getValueColumnName()).append(",");
          buffer.append(getGmtModifiedColumnName()).append(") values(?,?,?);");

          this.insertSql = buffer.toString();
        }
      }
    }
    return this.insertSql;
  }

  private String getSelectSql() {
    if (this.selectSql == null) {
      synchronized (this) {
        if (this.selectSql == null) {
          StringBuilder buffer = new StringBuilder();
          buffer.append("select ").append(getValueColumnName());
          buffer.append(" from ").append(getTableName());
          buffer.append(" where ").append(getNameColumnName()).append(" = ?");

          this.selectSql = buffer.toString();
        }
      }
    }

    return this.selectSql;
  }

  private String getUpdateSql() {
    if (this.updateSql == null) {
      synchronized (this) {
        if (this.updateSql == null) {
          StringBuilder buffer = new StringBuilder();
          buffer.append("update ").append(getTableName());
          buffer.append(" set ").append(getValueColumnName()).append(" = ?, ");

          buffer.append(getGmtModifiedColumnName()).append(" = ? where ");

          buffer.append(getNameColumnName()).append(" = ? and ");
          buffer.append(getValueColumnName()).append(" = ?");

          this.updateSql = buffer.toString();
        }
      }
    }

    return this.updateSql;
  }

  private static void closeResultSet(ResultSet rs) {
    if (rs != null)
      try {
        rs.close();
      } catch (SQLException e) {
        log.debug("Could not close JDBC ResultSet", e);
      } catch (Throwable e) {
        log.debug("Unexpected exception on closing JDBC ResultSet", e);
      }
  }

  private static void closeStatement(Statement stmt)
  {
    if (stmt != null)
      try {
        stmt.close();
      } catch (SQLException e) {
        log.debug("Could not close JDBC Statement", e);
      } catch (Throwable e) {
        log.debug("Unexpected exception on closing JDBC Statement", e);
      }
  }

  private static void closeConnection(Connection conn)
  {
    if (conn != null)
      try {
        conn.close();
      } catch (SQLException e) {
        log.debug("Could not close JDBC Connection", e);
      } catch (Throwable e) {
        log.debug("Unexpected exception on closing JDBC Connection", e);
      }
  }
 
原文地址:https://www.cnblogs.com/kaleidoscope/p/9779481.html