package message.datasource.key.generic;
import message.datasource.key.AbstractMaxValueIncrementer;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.jdbc.support.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
* SQL Server主键自增长策略
*
* @author sunhao(sunhao.java@gmail.com)
* @version V1.0, 2012-4-11 上午10:40:59
*/
public class SqlServerMaxValueIncrementer extends AbstractMaxValueIncrementer {
/** The current cache of values */
private long[] valueCache;
/** The next id to serve from the value cache */
private int nextValueIndex = -1;
/** The number of keys buffered in a cache */
private int cacheSize = 1;
protected synchronized long getNextKey(String name) throws DataAccessException {
if (this.nextValueIndex < 0 || this.nextValueIndex >= getCacheSize()) {
/*
* Need to use straight JDBC code because we need to make sure that the insert and select
* are performed on the same connection (otherwise we can't be sure that @@identity
* returnes the correct value)
*/
Connection con = DataSourceUtils.getConnection(getDataSource());
Statement stmt = null;
try {
stmt = con.createStatement();
DataSourceUtils.applyTransactionTimeout(stmt, getDataSource());
this.valueCache = new long[getCacheSize()];
this.nextValueIndex = 0;
for (int i = 0; i < getCacheSize(); i++) {
stmt.executeUpdate("insert into " + name + " default values");
ResultSet rs = stmt.executeQuery("select @@identity");
try {
if (!rs.next()) {
throw new DataAccessResourceFailureException("@@identity failed after executing an update");
}
this.valueCache[i] = rs.getLong(1);
}
finally {
JdbcUtils.closeResultSet(rs);
}
}
long maxValue = this.valueCache[(this.valueCache.length - 1)];
stmt.executeUpdate("delete from " +name + " where " + name + " < " + maxValue);
}
catch (SQLException ex) {
throw new DataAccessResourceFailureException("Could not increment identity", ex);
}
finally {
JdbcUtils.closeStatement(stmt);
DataSourceUtils.releaseConnection(con, getDataSource());
}
}
return this.valueCache[this.nextValueIndex++];
}
/**
* Return the number of buffered keys.
*/
public int getCacheSize() {
return cacheSize;
}
/**
* Set the number of buffered keys.
*/
public void setCacheSize(int cacheSize) {
this.cacheSize = cacheSize;
}
}