0

我刚刚创建了一个自定义休眠 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);
        }
    }
    }

我想知道:

  1. 我怎样才能使这个多交易安全?(即如果两个并发事务插入数据,我怎么能安全地假设我最终不会拥有两次相同的 ID?)——我想这里唯一的解决方案是防止两个并发的休眠事务同时运行如果他们使用相同的发电机,这可能吗?
  2. 如果代码可以改进:我觉得必须使用硬编码"select""target_column"等等......

为了保证第 1 点),如有必要,我可以在我的 java 客户端代码上同步插入时回退。

请不要评论我使用这种生成器的原因:遗留代码仍然将数据插入同一个数据库并使用这种机制......并且无法修改。是的,我知道,这很糟糕。

4

2 回答 2

2

我认为实现事务安全行为的最简单方法是将用于检索最大 id 并执行插入语句的代码放在事务块中。就像是:

Transaction transaction = session.beginTransaction();
//some code...
transaction.commit();
session.close()

我还建议尽可能使用 HQL(Hibernate Query Language)来创建查询,而不是使用原生 sql。此外,根据您的描述,我了解到您期望从查询中获得唯一的结果,即最大 id。因此,您可以在查询上使用 uniqueResult() 方法而不是 executeQuery。

于 2012-10-22T21:45:30.400 回答
0

您可以使用 AtomicInteger 生成 ID。这可以被许多线程同时使用。

如果您可以自由使用任何其他 ID 提供者,那么我会建议使用 UUID 类来生成随机 ID。

UUID.randomUUID();

您可以参考链接,其中包含其他一些生成 ID 的方法。

于 2012-10-23T07:34:54.823 回答