Remove an ancient TODO: Get rid of SELECT FOR UPDATE and instead locklessly claim the next available primary key value.
This commit is contained in:
@@ -123,36 +123,51 @@ public class TableValueGenerator extends ValueGenerator
|
|||||||
public int nextGeneratedValue (Connection conn, DatabaseLiaison liaison)
|
public int nextGeneratedValue (Connection conn, DatabaseLiaison liaison)
|
||||||
throws SQLException
|
throws SQLException
|
||||||
{
|
{
|
||||||
PreparedStatement stmt = null;
|
PreparedStatement readStatement = null;
|
||||||
|
PreparedStatement writeStatement = null;
|
||||||
try {
|
try {
|
||||||
// TODO: Make this lockless!
|
// TODO: Make this lockless!
|
||||||
String query =
|
readStatement = conn.prepareStatement(
|
||||||
" SELECT " + liaison.columnSQL(_valueColumnName) +
|
" SELECT " + liaison.columnSQL(_valueColumnName) +
|
||||||
" FROM " + liaison.tableSQL(_valueTable) +
|
" FROM " + liaison.tableSQL(_valueTable) +
|
||||||
" WHERE " + liaison.columnSQL(_pkColumnName) + " = ? FOR UPDATE";
|
" WHERE " + liaison.columnSQL(_pkColumnName) + " = ? ");
|
||||||
stmt = conn.prepareStatement(query);
|
readStatement.setString(1, _pkColumnValue);
|
||||||
stmt.setString(1, _pkColumnValue);
|
|
||||||
|
|
||||||
ResultSet rs = stmt.executeQuery();
|
writeStatement = conn.prepareStatement(
|
||||||
if (!rs.next()) {
|
|
||||||
throw new SQLException("Failed to find next primary key value " +
|
|
||||||
"[table=" + _valueTable + ", column=" + _valueColumnName +
|
|
||||||
", where=" + _pkColumnName + "=" + _pkColumnValue + "]");
|
|
||||||
}
|
|
||||||
int val = rs.getInt(1);
|
|
||||||
JDBCUtil.close(stmt);
|
|
||||||
|
|
||||||
stmt = conn.prepareStatement(
|
|
||||||
" UPDATE " + liaison.tableSQL(_valueTable) +
|
" UPDATE " + liaison.tableSQL(_valueTable) +
|
||||||
" SET " + liaison.columnSQL(_valueColumnName) + " = ? " +
|
" SET " + liaison.columnSQL(_valueColumnName) + " = ? " +
|
||||||
" WHERE " + liaison.columnSQL(_pkColumnName) + " = ?");
|
" WHERE " + liaison.columnSQL(_pkColumnName) + " = ? " +
|
||||||
stmt.setInt(1, val + _allocationSize);
|
" AND " + liaison.columnSQL(_valueColumnName) + " = ? ");
|
||||||
stmt.setString(2, _pkColumnValue);
|
|
||||||
stmt.executeUpdate();
|
for (int tries = 0; tries < 10; tries ++) {
|
||||||
return val;
|
// execute the query
|
||||||
|
ResultSet rs = readStatement.executeQuery();
|
||||||
|
if (!rs.next()) {
|
||||||
|
throw new SQLException(
|
||||||
|
"Failed to find next primary key value [table=" + _valueTable +
|
||||||
|
", column=" + _valueColumnName + "]");
|
||||||
|
}
|
||||||
|
// fetch the next available value
|
||||||
|
int val = rs.getInt(1);
|
||||||
|
|
||||||
|
// claim this value locklessly
|
||||||
|
writeStatement.setInt(1, val + _allocationSize);
|
||||||
|
writeStatement.setString(2, _pkColumnValue);
|
||||||
|
writeStatement.setInt(3, val);
|
||||||
|
|
||||||
|
// if we modified a row, we know we and nobody else got this particular value!
|
||||||
|
if (writeStatement.executeUpdate() == 1) {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
// else try again
|
||||||
|
}
|
||||||
|
throw new SQLException(
|
||||||
|
"Failed to claim next primary key value in 10 attempts [table=" + _valueTable +
|
||||||
|
", column=" + _valueColumnName + "]");
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
JDBCUtil.close(stmt);
|
JDBCUtil.close(readStatement);
|
||||||
|
JDBCUtil.close(writeStatement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user