SequenceGenerator 在 JUnit 测试中不起作用?

Posted

技术标签:

【中文标题】SequenceGenerator 在 JUnit 测试中不起作用?【英文标题】:SequenceGenerator does not work in JUnit test? 【发布时间】:2016-08-19 09:37:05 【问题描述】:

我尝试使用内存 H2 DB 测试某些实体的持久性,但我认识到@SequenceGenerator 永远不会被调用,无论是在构建平台运行时,还是在使用 RunAs 运行时-> Eclipse 中的 JUnit 测试。

我可以肯定地说,这些序列是在 H2 DB 内部生成的。当我连接到这个生成的 H2 时,我什至可以选择它们。所以这绝对不是 H2 内部的问题,而是 Hibernate 的问题。 (通常 Hibernate 在持久化需要一个 ID 的实体时会自动分配一个 ID)。

实体

@Entity
@Table(name = "HOUSE_USERDATA")
public class UserData 

@Id
@Column(name = "HU_ID")
@GeneratedValue(generator = "SEQ_HOUSE_USERDATA", strategy = GenerationType.SEQUENCE)
@SequenceGenerator(sequenceName = "SEQ_HOUSE_USERDATA", name = "SEQ_HOUSE_USERDATA", allocationSize = 2)
private Long huId;

@Column(name = "HU_DATA")
@Size(max = 1000)
private String m_data;

@ManyToOne
@JoinColumn(name = "HR_ID")
private Registry m_registry;

//more code [...]

引用实体中的引用...

  @OneToMany(mappedBy = "registry")
  private List<UserData> userDataList;

持久化单元...

<persistence-unit name="test" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <class>com.foo.bar.all.entity</class>
    <!-- all entity references -->
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <properties>
        <property name="hibernate.archive.autodetection" value="class"/>
        <property name="hibernate.connection.username" value="sa"/>
        <property name="hibernate.connection.password" value=""/>
        <property name="hibernate.connection.driver_class" value="org.h2.Driver"/>
        <property name="hibernate.connection.url" 
        value="jdbc:h2:inmemory;INIT=runscript from 'classpath:testscripts/drop_h2.sql'\;runscript from 'classpath:testscripts/create.sql'"/>
        <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
        <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
        <property name="hibernate.show_sql" value="true" />
        <property name="hibernate.format_sql" value="true" />
        <property name="hibernate.use_sql_comments" value="true" />
    </properties>
</persistence-unit>

JUnit 测试中的调用...

Registry registry = new Registry();
registry.setClientId("clientId");
List<UserData> userDataList = new ArrayList<>();
UserData userData1 = new UserData();
userData1.setData("User defined data 1.");
userData1.setRegistry(registry);
UserData userData2 = new UserData();
userData2.setData("User defined data 2.");
userData2.setRegistry(registry);
userDataList.add(userData1);
userDataList.add(userData2);
registry.setUserDataList(userDataList);


entityManager.persist(registry);


Registry result = entityManager.find(Registry.class, "clientId");
//MUST NOT BE NULL, BUT IS NULL
assertThat(result.getUserDataList().get(0).getId(), is(not(nullValue())))

其他值已正确保留。只有 ID 没有生成。 (我想知道为什么这个测试对所有其他值都有效,因为在生成的数据库中 ID 被定义为 NOT NULL,所以应该有一个持久性异常或其他东西)。 任何想法为什么序列生成器不生成任何东西(我也试过GenerationType.AUTO,但没有区别)?

【问题讨论】:

因为它没有被告知这样做。您正在保留 RegistryUserData 对象的集合没有级联属性。这意味着只有*** Registry 将被保存,而不是单个 UserData 对象。数据库中没有任何内容,您从entityManager.find 方法返回的是存储在一级缓存中的对象,而不是来自数据库的对象。如果您在find 之前执行entityManager.clear(),您将获得一个没有UserData 对象的Registry 实例。 【参考方案1】:

当您正在执行entityManager.persist(registry) 时,它会执行此操作,存储Registry 并检查该类的所有映射。它将遇到UserData 对象的集合,但由于没有与PERSIST 匹配的cascade 属性,它不会存储UserData 对象。

它只会存储***Registry 对象。如果你想改变这个添加cascade=CascadeType.ALL或至少cascade=CascadeType.PERSIST@OneToMany注解,告诉Hibernate它还需要检查新元素的集合并持久化这些元素。

或者在存储Registry 之前先存储UserData 元素。

【讨论】:

以上是关于SequenceGenerator 在 JUnit 测试中不起作用?的主要内容,如果未能解决你的问题,请参考以下文章

HSQLDB 和 SequenceGenerator 的问题

JPA @SequenceGenerator 注释如何工作

为啥 PostgreSql 的 Hibernate 默认生成器是“SequenceGenerator”,而不是“IdentityGenerator”?

markdown JPA - SequenceGenerator

hibernate 注解之 SequenceGenerator

Flink SQL 使用 Datagen SequenceGenerator 出现 OutOfMemoryError: Java heap space 异常