1

我有一个 JPA 实体,其 TableGenerator 分配大小 = 25。如果我要手动更新 TableGenerator 表并为下一个 ID 开始范围赋予一个新值,则在当前范围过去之前它不会生效。

例如,如果当前 TableGenerator 表值为 10,我将开始获取实体 ID 250、251、252 等。在 255 时,我将 TableGenerator 表值更改为 20。但是,下一个 ID 仍将是 256 , 257,一直到 274,那么下一个 ID 将是 500。

当然,这是很自然的——但我想知道,有没有办法告诉 Hibernate 暂时忽略当前间隔并开始从 TableGenerator 表中的任何内容分配 ID?


因此,在我的特殊情况下,要回答重要的原因:

我正在为我的团队的产品开发一个测试自动化工具,一方面,它能够通过正在运行的系统(使用客户端应用程序、API 等)设置测试数据。测试数据配置(我们称它们为测试数据)被定义为可以将多个测试数据一起用于特定的测试用例/测试套件。

现在,一旦运行测试数据,该工具将从数据库中提取输入的数据到 SQL 插入语句中,并将它们存储到文件中。这有几个原因,但主要是关于性能 - 如果我想用某个测试数据运行 100 个测试用例,我只真正关心“手动”插入一次测试数据,然后每次重置时,我可能会采用更快的方法将测试数据直接插入数据库。

但是,正如我所说,几个测试数据可以一起使用。如果 testdata01 和 testdata02 都影响同一个表怎么办?如果事先已经运行了另一个,则提取的 SQL 插入语句将不会仅包含该特定测试数据的数据。

一个简单的解决方案是为每个测试数据保留一个 ID 间隔。对于每个表,testdata01 的区间为 [10000, 20000),testdata02 的区间为 [20000, 30000),依此类推。这很容易实现——在运行每个 testdata 之前,只需将所有 TableGenerator 表更新到 testdata 的 ID 区间的下限——然后,在运行 testdata 设置之后,只提取 ID 在区间内的行。

这很好用,并确保测试数据之间的 ID 永远不会发生任何冲突,并且每个测试数据的导出 SQL 仅包含该特定测试数据的数据,而不管当时数据库中可能还有什么。但是,allocationSize 不为 1 的这一点会搞砸 - 即使我们已经更新了实体的 TableGenerator,条目仍可能出现在给定实体的保留 ID 间隔之外。

所以,简而言之,我想做的是,在更新 TableGenerator 表之后,在开始运行 testdata 设置之前,我想告诉 Hibernate 对于每个实体,下次生成 ID 时,忽略接下来的任何内容您想从该 TableGenerator 的范围生成的值,而是检查数据库中的 TableGenerator 表,以了解下一个要使用的范围。

4

1 回答 1

1

所以我设法自己抓了这个。如果有人有相同的需求,供将来参考:

public void moveToNextInterval(Class entity, javax.persistence.EntityManager em) throws IllegalAccessException, InstantiationException {
    javax.persistence.TableGenerator tableGenerator = null;
    for (Method method : entity.getMethods()) {
        tableGenerator = method.getAnnotation(javax.persistence.TableGenerator.class);
        if (tableGenerator != null) {
            break;
        }
    }
    if (tableGenerator != null && tableGenerator.allocationSize() > 1) {
        int allocationSize = tableGenerator.allocationSize();
        org.hibernate.impl.SessionImpl session = (org.hibernate.impl.SessionImpl) em.unwrap(org.hibernate.Session.class);
        IdentifierGenerator idGenerator = session.getFactory().getIdentifierGenerator(entity.getName());
        while ((Long)idGenerator.generate(session, entity.newInstance()) % allocationSize != allocationSize - 1);
    }
}

还不太习惯 Hibernate 或 JPA,所以可能有很多可能的改进。对于任何类型的序列生成器,概括这一点应该不难。此外,您可能只需要创建一个实体实例并重用它。此外,我猜还有超出预期 ID 的风险;例如,如果 allocationSize=25 并且最后一个 ID 是 24,并且我们已经更新了 TableGenerator 表并将其设置为 10,那么调用此方法实际上将使其下一个 ID 将是 275 而不是 250。好足以满足我的目的,但很高兴知道。

于 2013-08-16T14:20:08.420 回答