JPA @SequenceGenerator注释的工作原理

我正在学习JPA,在注释中有困惑。@SequenceGenerator

根据我的理解,它会自动为实体的数字标识字段/属性分配一个值。

问题 1.此序列生成器是利用数据库不断增加的数值生成功能还是自行生成数字?

问题 2.如果 JPA 使用数据库自动增量功能,那么它是否适用于没有自动增量功能的数据存储?

问题 3.如果 JPA 自己生成数值,那么 JPA 实现如何知道接下来要生成哪个值?它是否首先咨询数据库以查看最后存储的值以生成值(最后 + 1)?


问题 4.还请阐明注释的一些内容和属性。sequenceNameallocationSize@SequenceGenerator


答案 1

sequenceName是 DB 中序列的名称。您可以按照此方式指定数据库中已存在的序列。如果采用此路由,则必须指定哪个值必须与数据库序列用作其“自动增量”的值相同。allocationSize

用法:

@GeneratedValue(generator="my_seq")
@SequenceGenerator(name="my_seq",sequenceName="MY_SEQ", allocationSize=1)

如果需要,您可以让它为您创建一个序列。但要执行此操作,您必须使用架构生成来创建它。为此,请使用:

@GeneratedValue(strategy=GenerationType.SEQUENCE)

此外,您还可以使用自动生成,它将使用表来生成 ID。使用此功能时,还必须在某个时候使用架构生成,以便可以创建生成器表。为此,请使用:

@GeneratedValue(strategy=GenerationType.AUTO)

答案 2

尽管这个问题已经很老了,但我偶然发现了它,因为我自己在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.mergeem.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。否则会导致错误。


推荐