我很难理解当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 {
...
}
在创建地址之前,地址类型必须存在于数据库(CascadeType.MERGE)中。将使用新地址创建一个新组织,并且该地址具有从给定选择中设置的类型=>当有一个干净的数据库(仅存在地址类型)时,这可以正常工作。
仍在开发中,所以我时不时会关闭服务器(JVM)并重新启动应用程序。然后,我想将一个新的组织添加到数据库中,该数据库已经包含以前会话中保存的数据,然后我得到以下错误:
异常[EclipseLink-4002](Eclipse Persistence Services-2.5.0.v20130507-3faac2b):org.Eclipse.Persistence.exceptions.DatabaseException
内部异常:java.sql。SQLIntegrityConstraintViolationException:该语句已中止,因为它将导致由“ADDRESS”上定义的“SQL151120084237691”标识的唯一或主键约束或唯一索引中的键值重复。
错误代码:-20001
调用:插入“地址”(“ADDRESS_ID”、“STREET_ADDRESS”、“COUNTRY”、“ZIP_CODE”、“CITY”和“ADDRESS_TYPE_ID”)值(?、?、
绑定=>[2,测试道路1,国家,99999,测试城市,ABCDEF-123456]
它尝试使用与数据库中已存在的ID相同的ID。我如何让它意识到id已经被使用,并且应该从最后一次继续使用?
笔记:
-地址作为组织的一部分(CascadeType.ALL)而不是单独保存。
-在测试中,我将所有现有组织加载到执行持久化操作的同一EntityManager中=>该组织急切地访问其地址,因此它们应该在em缓存中可用。它在单元测试中抱怨的重复address_id似乎是一个孤立的实体(也许这实际上是错误的原因?)。
-我可以在使用Derby的单元测试中得到这个错误,但使用OracleDB的测试服务器在日志中也有这些错误。
-我还尝试添加“查找所有”查询,将所有地址实体加载到执行组织持久化操作的同一EntityManager的缓存中。在持久化完成之前执行“查找所有”=>它仍然失败了。
//更新
即使我使用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;
...
}
生成器表已创建,但仍为空。然而,id从初始值“100”开始运行。
更多注意事项:
-当使用自定义表并在其中为序列插入值时,地址实体的id将从该值正确地继续。测试完成后,表将被清空,而表中仍有数据=>下次会失败。
-使用GenerationType时。AUTO,序列表得到一个默认序列,但在测试后它被清除(与自定义表相同)
^我想这是在测试服务器中发生的,可以通过在测试后不清空数据库来复制。然而,序列表被清空。因此,问题是,如何在JVM启动后同步序列表(或防止其自身不清空)?