Hi Geoff
I didn't submit a patch to the community. Please find the sample code for reference.
Code:
public class BatchSqlServerMaxValueIncrementer extends SqlServerMaxValueIncrementer {
/** Containing Logger for the Class. */
private static final Logger LOGGER = Logger.getLogger(BatchSqlServerMaxValueIncrementer.class);
/** Dead lock error code.*/
private static final long DEADLOCK_ERROR_CODE = 1205;
/** The deadlock error code. */
private int deadLockErrorCode;
/** The retryLimit. */
private int retryLimit;
/** The sleepTime. */
private int sleepTime;
/**
* Default constructor for bean property style usage.
*
* @see #setDataSource
* @see #setIncrementerName
* @see #setColumnName
*/
public BatchSqlServerMaxValueIncrementer() {
}
/**
* BatchSqlServerMaxValueIncrementer constructor.
*
* @param dataSource
* the data source.
* @param incrementerName
* the incrementerName
* @param columnName
* the columnName
* @param deadLockErrorCode
* the deadLockErrorCode.
* @param retryLimit
* the retryLimit.
* @param sleepTime
* the sleepTime.
*/
public BatchSqlServerMaxValueIncrementer(DataSource dataSource, String incrementerName, String columnName,
int deadLockErrorCode, int retryLimit, int sleepTime) {
super(dataSource, incrementerName, columnName);
this.deadLockErrorCode = deadLockErrorCode;
this.retryLimit = retryLimit;
this.sleepTime = sleepTime;
}
/**
* get the getNextKey value.
*
* @return identity value
*/
protected synchronized long getNextKey() {
LOGGER.debug("Enter getNextKey.");
long lCurrentId;
lCurrentId = getNextIdLot();
LOGGER.debug("Exit getNextKey.");
return lCurrentId;
}
/**
* getNextIdLot get the new connection and do an insert and select with in the same transaction.
*
* @return the incremented value.
*/
private long getNextIdLot() {
LOGGER.debug("Enter getNextIdLot.");
Connection con = null;
int retryCount = 0;
long nextIdValue = 0;
/*
* 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
* returns the correct value)
*/
try {
con = DataSourceUtils.getConnection(getDataSource());
do {
try {
nextIdValue = getNextLotStartNumber(con);
con.commit();
break;
} catch (SQLException lSQLException) {
try {
if (isDeadLockTimeout(lSQLException)) {
con.rollback();
con.setAutoCommit(false);
retryCount++;
sleep(sleepTime);
} else {
throw lSQLException;
}
} catch (SQLException e) {
throw new DataAccessResourceFailureException("Unable to Rollback", e);
}
if (retryCount == retryLimit) {
LOGGER.error("Retry failed with ErrorCode: " + lSQLException.getErrorCode());
//Throw system exception
}
}
} while (retryCount <= retryLimit);
} finally {
DataSourceUtils.releaseConnection(con, getDataSource());
}
LOGGER.debug("Exit getNextIdLot.");
return nextIdValue;
}
/**
* getNextLotStartNumber set auto commit to false and get the next id value from SEQ table.
*
* @param connection
* the connection.
* @return the currentValue.
* @throws SQLException
* the sql exception
*/
private synchronized long getNextLotStartNumber(Connection connection) throws SQLException {
LOGGER.debug("Enter getNextLotStartNumber.");
long nextIdValue;
Statement stmt = null;
try {
connection.setAutoCommit(false);
stmt = connection.createStatement();
nextIdValue = getNextIDValue(connection, stmt);
} finally {
JdbcUtils.closeStatement(stmt);
}
LOGGER.debug("Exit getNextLotStartNumber.");
return nextIdValue;
}
/**
* Get the incremented value by using update and select.
*
* @param connection
* the connection
* @param statement
* the statement
* @return the currentValue.
* @throws SQLException
* the SQLException
*/
private long getNextIDValue(Connection connection, Statement statement) throws SQLException {
LOGGER.debug("Enter getNextIDValue.");
ResultSet resultSet = null;
long nextIDValue;
try {
statement.executeUpdate("UPDATE " + getIncrementerName() + " SET ID = ID + 1");
resultSet = statement.executeQuery("select ID from " + getIncrementerName());
if (!resultSet.next()) {
throw new DataAccessResourceFailureException("Fetching identity for " + getIncrementerName()
+ " + failed.");
}
nextIDValue = resultSet.getLong(1);
} finally {
JdbcUtils.closeResultSet(resultSet);
}
LOGGER.debug("Exit getNextIDValue.");
return nextIDValue;
}
/**
* Sleep.
*
* @param sleepTime
* the sleep time
*/
private void sleep(int sleepTime) {
try {
Thread.sleep(sleepTime);
} catch (InterruptedException interruptedException) {
LOGGER.error(interruptedException);
}
}
/**
* validate the deadlock timeout and dead lock error code.
*
* @param lSQLException
* the SQLException
* @return deadLockTimeout indicator
*/
private boolean isDeadLockTimeout(SQLException lSQLException) {
return (lSQLException.getErrorCode() == deadLockErrorCode
|| lSQLException.getErrorCode() == DEADLOCK_ERROR_CODE);
}
}