Java 强制具有allocationSize的TableGenerator跳到下一个间隔

Java 强制具有allocationSize的TableGenerator跳到下一个间隔,java,hibernate,jpa,Java,Hibernate,Jpa,我有一个JPA实体,其TableGenerator的allocationSize=25。如果手动更新TableGenerator表,并为下一个ID开始范围赋予一个新值,则在当前范围过去之前不会产生效果 例如,如果当前TableGenerator表的值为10,我将开始获取实体ID为250、251、252等。在255处,我将TableGenerator表的值更改为20。但是,下一个ID仍然是256257,一直到274,那么下一个ID将是500 当然,这是很自然的——但我想知道,有没有办法让Hiber

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

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

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


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

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

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

然而,正如我所说的,几个测试数据可以一起使用。如果testdata01和testdata02都影响相同的表呢?如果事先已经运行了另一个语句,则提取的SQL insert语句将不会只包含该特定testdata的数据

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

这非常有效,并确保testdata之间的ID不会发生任何冲突,并且每个testdata的导出SQL只包含该特定testdata的数据,而不管当时数据库中还有哪些数据。但是,allocationSize不是1的这一点会把事情搞砸-条目可能仍然会出现给定实体的保留ID间隔的一侧,即使我们已经更新了该实体的TableGenerator


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

因此我自己设法划掉了这个范围。如果有人有同样的需要,请参考:

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;例如,如果Size=25,最后一个ID是24,我们已经更新了TableGenerator表并将其设置为10,然后调用此方法将使下一个ID实际上为275,而不是250。对于我的目的来说,这已经足够了,但很好知道。

因此我自己设法抓取了这一个。如果有人有同样的需要,请参考:

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;例如,如果Size=25,最后一个ID是24,我们已经更新了TableGenerator表并将其设置为10,然后调用此方法将使下一个ID实际上为275,而不是250。对于我来说,这已经足够好了,但很高兴知道。

你会得到什么?有什么意义?ID必须是唯一的,这就是它们应该有的。如果ID有特定的函数意义,那么它不应该是实体的PK,而应该是一个函数字段,有一个特定的生成器。@jbnize我大部分都明白了,这是不相关的。我很惊讶地发现这一点的必要性,并且对有人分享这个用例几乎没有希望。我更新了这个问题,解释了原因这在我的特殊情况下会很有用。+1是一个很好的解释。你会得到什么?有什么意义?ID必须是唯一的,这就是它们应该是的。如果ID有特定的功能含义,那么它不应该是实体的PK,而应该是一个功能字段,带有特定的生成器。@jbnize我大部分不知道,这不会是be相关。我自己很惊讶地发现这一点的必要性,也不希望有人分享这个用例。我已经更新了这个问题,解释了为什么这在我的特定案例中会有用。好的解释是+1。