JPA 2,理解 CascadeType.ALL 和 GenerationType.AUTO (EclipseLink 2.5)

JPA 2, understanding CascadeType.ALL and GenerationType.AUTO (EclipseLink 2.5)

我无法理解当 JVM 已重新启动且数据库已包含先前会话的数据时如何正确地保留具有子实体的实体。

我大致有以下实体:

@Entity
public class Organization {
    ...
    @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
    @JoinColumn(name = "\"ADDRESS_ID\"", nullable = false)
    private Address address;
}

@Entity
public class Address {
    ...
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "\"ADDRESS_ID\"")
    private int addressId;
    @ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.MERGE, optional = false)
    @JoinColumn(name = "\"ADDRESS_TYPE_ID\"", nullable = false)
    private AddressType addressType;
}

@Entity
public class AddressType {
    ...
    // Not bi-directional, so nothing special here
}

在创建地址之前,地址类型应该存在于数据库中 (CascadeType.MERGE)。使用新地址创建一个新组织,并且该地址具有从给定选择中设置的类型。 => 这在有干净的数据库(仅存在地址类型)时工作正常。

仍在开发中,所以我时不时地关闭服务器 (JVM) 并重新启动应用程序。然后我想将一个新组织添加到数据库中,该数据库已经包含以前会话中保留的数据,然后我收到以下错误:

Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.DatabaseException Internal Exception: java.sql.SQLIntegrityConstraintViolationException: The statement was aborted because it would have caused a duplicate key value in a unique or primary key constraint or unique index identified by 'SQL151120084237691' defined on 'ADDRESS'. Error Code: -20001 Call: INSERT INTO "ADDRESS" ("ADDRESS_ID", "STREET_ADDRESS", "COUNTRY", "ZIP_CODE", "CITY", "ADDRESS_TYPE_ID") VALUES (?, ?, ?, ?, ?, ?) bind => [2, testroad 1, Country, 99999, testcity, ABCDEF-123456]

它尝试使用数据库中已存在的相同 ID。我如何让它意识到该 id 已被使用并且应该从上一个继续?

备注:
- 地址作为组织的一部分 (CascadeType.ALL) 而不是单独保存。
- 在测试中,我将所有现有的组织加载到执行持久操作的同一个 EntityManager => 该组织的地址被急切访问,因此它们应该在 em-cache 中可用。它在单元测试中抱怨的重复 address_id 似乎是一个孤立的实体(也许这实际上是错误的原因?)。
- 我可以在使用 Derby 的单元测试中得到这个错误,但是使用 Oracle DB 的测试服务器在日志中有这些相同的错误。
- 我还尝试添加一个 'find all' 查询以将所有地址实体加载到执行组织持久操作的同一 EntityManager 的缓存中。 'find all' 在持久化完成之前执行 => 它仍然失败。

//更新
即使我使用 TableGenerator 获取 id 值也会发生同样的事情。

@Entity
public class Address {
...
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator = "addr_gen")
    @TableGenerator(name = "addr_gen", allocationSize = 1, initialValue = 100, table = "\"ADDRESS_GEN\"")
    @Column(name = "\"ADDRESS_ID\"")
    private int osoiteId;
    ...
}

生成器 table 已创建,但仍为空。然而,id 从“100”的初始值 运行 开始。

更多注意事项:
- 当使用自定义 table 并为序列插入一个值时,地址实体的 ID 从该值正确继续。当测试结束时,table 被清空,而 tables 中仍有数据 => 下次将失败。 - 当使用 GenerationType.AUTO 时,序列 table 获得默认序列,但在测试后它被清除(与自定义 table 相同)

^我猜这在测试服务器中发生过,并且可以通过在测试后不清空数据库来复制它。但是序列 table 被清空。所以问题是,如何在 JVM 启动后同步序列 table(或防止它不清空自身)?

我不知道这是否是一个很好的解决方案,或者对于原始主题来说是否总体上是正确的,但我设法通过为所有自动生成的 ID 字段单独定义序列来做出某种解决方法。

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "addrSeq")
@SequenceGenerator(name = "addrSeq", sequenceName = "addr_seq", allocationSize = 10)
@Column(name = "\"ADDRESS_ID\"")
private int addressId;

它似乎有效,但我不知道为什么它的行为与使用 'AUTO' 有本质上的不同? 服务器重启时默认序列为空是否正常?