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初始化完成:\r\n ");
sb.append("appName:").append(this.appName).append("\r\n");
sb.append("innerStep:").append(this.innerStep).append("\r\n");
sb.append("dataSource:").append(this.dscount).append("个:");
for (String str : this.dbGroupKeys) {
sb.append("[").append(str).append("]、");
}
sb.append("\r\n");
sb.append("adjust:").append(this.adjust).append("\r\n");
sb.append("retryTimes:").append(this.retryTimes).append("\r\n");
sb.append("tableName:").append(this.tableName).append("\r\n");
sb.append("nameColumnName:").append(this.nameColumnName).append("\r\n");
sb.append("valueColumnName:").append(this.valueColumnName).append("\r\n");
sb.append("gmtModifiedColumnName:").append(this.gmtModifiedColumnName).append("\r\n"); 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);
}
}
TDDL实践的更多相关文章
- mongodb 最佳实践
MongoDB功能预览:http://pan.baidu.com/s/1k2UfW MongoDB在赶集网的应用:http://pan.baidu.com/s/1bngxgLp MongoDB在京东的 ...
- 【大数据和云计算技术社区】分库分表技术演进&最佳实践笔记
1.需求背景 移动互联网时代,海量的用户每天产生海量的数量,这些海量数据远不是一张表能Hold住的.比如 用户表:支付宝8亿,微信10亿.CITIC对公140万,对私8700万. 订单表:美团每天几千 ...
- TDDL调研笔记
一,TDDL是什么 Taobao Distributed Data Layer,即淘宝分布式数据层,简称TDDL .它是一套分布式数据访问引擎 淘宝一个基于客户端的数据库中间件产品 基于JDBC规范, ...
- 分库分表技术演进&最佳实践
每个优秀的程序员和架构师都应该掌握分库分表,这是我的观点. 移动互联网时代,海量的用户每天产生海量的数量,比如: 用户表 订单表 交易流水表 以支付宝用户为例,8亿:微信用户更是10亿.订单表更夸张, ...
- webp图片实践之路
最近,我们在项目中实践了webp图片,并且抽离出了工具模块,整合到了项目的基础模板中.传闻IOS10也将要支持webp,那么使用webp带来的性能提升将更加明显.估计在不久的将来,webp会成为标配. ...
- Hangfire项目实践分享
Hangfire项目实践分享 目录 Hangfire项目实践分享 目录 什么是Hangfire Hangfire基础 基于队列的任务处理(Fire-and-forget jobs) 延迟任务执行(De ...
- TDD在Unity3D游戏项目开发中的实践
0x00 前言 关于TDD测试驱动开发的文章已经有很多了,但是在游戏开发尤其是使用Unity3D开发游戏时,却听不到特别多关于TDD的声音.那么本文就来简单聊一聊TDD如何在U3D项目中使用以及如何使 ...
- Logstash实践: 分布式系统的日志监控
文/赵杰 2015.11.04 1. 前言 服务端日志你有多重视? 我们没有日志 有日志,但基本不去控制需要输出的内容 经常微调日志,只输出我们想看和有用的 经常监控日志,一方面帮助日志微调,一方面及 ...
- 【大型网站技术实践】初级篇:借助Nginx搭建反向代理服务器
一.反向代理:Web服务器的“经纪人” 1.1 反向代理初印象 反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从 ...
随机推荐
- Linux入门进阶第二天——软件安装管理(上)
一.大纲介绍 这里介绍的仅仅是两大家族之一的RPM,关于Debian家族的DPKG,请参考:http://justcoding.iteye.com/blog/1937171 二.简介 软件包分类: 源 ...
- 第三次随笔——虚拟机及Linux入门
虚拟机及Linux入门 虚拟机的安装 对于虚拟机的概念我早有接触,但是从来没有真正的实践过,借这次作业机会我终于实践了虚拟机的安装,安装的过程较为顺利,但还是出现了以下问题: 无法选择64位的系统 解 ...
- 【java笔记】Calendar.getInstance()是什么意思
Calendar类是个抽象类,因此本身不能被实例化,然而在却创建了Calendar 的对象,但并不是抽象类可以创建对象这个对象并不是Calendar 自身实例,而是其子类实例,这是在getInstan ...
- Apache入门篇(四)之LAMP架构部署
一.LAMP解析 a: apachem: mariadb, mysqlp: php, perl, python 静态资源:静态内容:客户端从服务器获得的资源的表现形式与原文件相同:动态资源:通常是程序 ...
- [Bootstrap 源码解析]——bootstrap源码之初始化
bootstrap源码之初始化 我们先来分析normalize.less编译后的源码,我们知道normalize.css是一个专门将不同浏览器的默认css特性设置为统一效果的css库,它和reset. ...
- 安装centos minimal 版本后安装mysql详细过程(linux)
本文内容参考自:http://www.centoscn.com/mysql/2014/1211/4290.html PS:Yum(全称为 Yellow dog Updater, Modified)是一 ...
- 查询表的大小(mysql)
--所有表的大小 select concat(round(sum(DATA_LENGTH/1024/1024),2),'M') from information_schema.tables where ...
- Unity Lighting - Light Types 灯光类型(八)
Light Types 灯光类型 We have now covered some of the project settings which need to be considered befo ...
- Spine with Unity Mecanim
前言 最近这两天刚刚接触Spine,研究了一下Unity Mecanim Animator如何控制Spine,在此分享记录一下,如有不当之处,请留言指出,欢迎讨论. Unity & Spine ...
- C语言零碎知识点
1. int整形在64位和32位计算机中都占4个字节. 指针在64位占8个字节,32位占4个字节. 2. 数组下标从0开始,a[0]开始,链表下标从1开始,a[1]开始. 3. 条件运算符(con ...