使用allocationSize强制TableGenerator跳到下一个间隔

时间:2013-08-13 10:28:31

标签: java hibernate jpa

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

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

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


所以,回答大为什么,在我的特定情况下:

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

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

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

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

这很好用,并且确保testdatas之间的ID永远不会发生任何冲突,并且每个testdata的导出SQL只包含该特定testdata的数据,无论当时数据库中还有什么。但是,allocateSize不是1的一件事情 - 事情可能仍然出现在给定实体的保留ID间隔之外,即使我们已经更新了该实体的TableGenerator。

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

1 个答案:

答案 0 :(得分: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。足够我的目的,但很高兴知道。