尽管这个问题已经很老了,但我偶然发现了它,因为我自己在JPA 2.0和Oracle序列方面遇到了这个问题。
想分享我对一些事情的研究 -
在数据库序列定义中,GenerationType.SEQUENCE 的@SequenceGenerator(allocationSize)与 INCREMENT BY 之间的关系
确保@SequenceGenerator(allocationSize) 设置为与数据库序列定义中的 INCREMENT BY 相同的值,以避免出现问题(这同样适用于初始值)。
例如,如果我们在数据库中定义序列,其增量 BY 值为 20,则将 SequenceGenerator 中的分配大小也设置为 20。在这种情况下,JPA 不会调用数据库,直到它达到下一个 20 标记,同时它在内部将每个值递增 1。这将保存数据库调用,以便每次都获取下一个序列号。这样做的副作用是 - 每当重新部署应用程序或服务器在两者之间重新启动时,它将调用数据库以获取下一批,您将看到序列值中的跳转。此外,我们需要确保数据库定义和应用程序设置同步,这可能并不总是可能的,因为它们都由不同的组管理,您可能会很快失去控制。如果数据库值小于分配大小,您将看到由于 Id 的重复值而导致的 PrimaryKey 约束错误。如果数据库值大于分配大小,您将看到 Id 值的跳转。
如果数据库序列 INCREMENT BY 设置为 1(这是 DBA 通常执行的操作),请将 allocationSize 也设置为 1,以便它们同步,但 JPA 每次调用数据库以获取下一个序列号。
如果不希望每次都调用数据库,请使用 GenerationType.IDENTITY 策略,并通过数据库触发器设置@Id值。使用GenerationType.IDENTITY,一旦我们调用em.persist,对象就会保存到DB中,并将id的值分配给返回的对象,因此我们不必执行em.merge或em.flush。(这可能是特定于 JPA 提供程序的。不确定)
另一件重要的事情——
JPA 2.0 自动运行 ALTER SEQUENCE 命令以同步数据库序列中的分配大小和 INCREMENT BY。由于我们主要使用不同的模式名称(应用程序用户名),而不是序列存在的实际模式,并且应用程序用户名将不具有 ALTER SEQUENCE 权限,因此您可能会在日志中看到以下警告 -
000004c1 Runtime W CWWJP9991W: openjpa.运行时:警告:无法缓存序列“RECORD_ID_SEQ”的序列值。您的应用程序没有运行 ALTER SEQUENCE 命令的权限。确保它具有运行 ALTER SEQUENCE 命令的适当权限。
由于 JPA 无法更改序列,因此 JPA 每次都调用数据库以获取下一个序列号,而不管 @SequenceGenerator.allocationSize 的值如何。这可能是我们需要注意的不必要的后果。
要让 JPA 不运行此命令,请设置此值 - 在持久性.xml。这可确保 JPA 不会尝试运行 ALTER SEQUENCE 命令。它写了一个不同的警告 -
00000094 Runtime W CWWJP9991W: openjpa.Runtime: Warn:属性 “openjpa.jdbc.DBDictionary=disableAlterSeqenceIncrementBy” 设置为 true。这意味着“改变序列...增量 BY' SQL 语句将不会对序列“RECORD_ID_SEQ”执行。OpenJPA 执行此命令以确保在数据库中定义的序列的 INCREMENT BY 值与实体序列中定义的 allocationSize 相匹配。禁用此 SQL 语句后,用户有责任确保实体的序列定义与数据库中定义的序列匹配。
如警告中所述,这里很重要的一点是,我们需要确保数据库序列定义中的@SequenceGenerator.allocationSize 和 INCREMENT BY 是同步的,包括默认值 @SequenceGenerator(allocationSize) 为 50。否则会导致错误。