我刚刚创建了一个自定义休眠 ID 生成器,由于我不是休眠专家,我想获得一些关于我的代码的反馈。生成的 ID 为select max(id) from table
, +1。
public class MaxIdGenerator implements IdentifierGenerator, Configurable {
private Type identifierType;
private String tableName;
private String columnName;
@Override
public void configure(Type type, Properties params, Dialect dialect) {
identifierType = type;
tableName = (String) params.getProperty("target_table");
columnName = (String) params.getProperty("target_column");
}
@Override
public synchronized Serializable generate(SessionImplementor session,
Object object) {
return generateHolder(session).makeValue();
}
protected IntegralDataTypeHolder generateHolder(SessionImplementor session) {
Connection connection = session.connection();
try {
IntegralDataTypeHolder value = IdentifierGeneratorHelper
.getIntegralDataTypeHolder(identifierType
.getReturnedClass());
String sql = "select max(" + columnName + ") from " + tableName;
PreparedStatement qps = connection.prepareStatement(sql);
try {
ResultSet rs = qps.executeQuery();
if (rs.next())
value.initialize(rs, 1);
else
value.initialize(1);
rs.close();
} finally {
qps.close();
}
return value.copy().increment();
} catch (SQLException e) {
throw new IdentifierGenerationException(
"Can't select max id value", e);
}
}
}
我想知道:
- 我怎样才能使这个多交易安全?(即如果两个并发事务插入数据,我怎么能安全地假设我最终不会拥有两次相同的 ID?)——我想这里唯一的解决方案是防止两个并发的休眠事务同时运行如果他们使用相同的发电机,这可能吗?
- 如果代码可以改进:我觉得必须使用硬编码
"select"
,"target_column"
等等......
为了保证第 1 点),如有必要,我可以在我的 java 客户端代码上同步插入时回退。
请不要评论我使用这种生成器的原因:遗留代码仍然将数据插入同一个数据库并使用这种机制......并且无法修改。是的,我知道,这很糟糕。