我刚刚创建了一个自定义的hibernate ID生成器,因为我不是一个hibernate专家,我想得到一些关于我的代码的反馈。生成的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);
}
}
}
我想知道:
"select"
,"target_column"
等... 为了保证第1点),如果有必要,我可以在我的java客户端代码上同步插入时回退。
请不要评论我使用这种生成器的原因:遗留代码仍然将数据插入到同一个数据库中并使用此机制......并且无法修改。是的,我知道,这很糟糕。
答案 0 :(得分:2)
我认为实现事务安全行为的最简单方法是在事务块中放置用于检索最大id的代码并执行insert语句。 类似的东西:
Transaction transaction = session.beginTransaction();
//some code...
transaction.commit();
session.close()
我还建议使用HQL(Hibernate Query Language)来创建查询,而不是在可能的情况下使用本机sql。此外,根据您的描述,我已经了解您希望从查询中获得唯一的结果,即最大ID。因此,您可以在查询中使用uniqueResult()方法而不是executeQuery。
答案 1 :(得分:0)
您可以使用AtomicInteger生成ID。这可以被许多线程同时使用。
如果您可以自由使用任何其他ID提供程序,那么我建议使用UUID类生成随机ID。
UUID.randomUUID();
您可以参考link,其中包含一些其他生成ID的方法。