我正在学习JPA并且在@SequenceGenerator
注释中感到困惑。
据我了解,它会自动为实体的数字标识字段/属性赋值。
Q1。此序列生成器是否利用数据库增加的数值生成功能或自行生成数字?
Q2。如果JPA使用数据库自动增量功能,那么它是否可以使用没有自动增量功能的数据存储?
Q3。如果JPA自己生成数值,那么JPA实现如何知道接下来要生成哪个值?是否先咨询数据库以查看最后存储的值以生成值(last + 1)?
<小时/> 问题4。请同时了解
sequenceName
注释的allocationSize
和@SequenceGenerator
属性。
答案 0 :(得分:54)
sequenceName
是数据库中序列的名称。这是您指定DB中已存在的序列的方法。如果你走这条路线,你必须指定allocationSize
,它需要与DB序列用作“自动增量”的值相同。
用法:
@GeneratedValue(generator="my_seq")
@SequenceGenerator(name="my_seq",sequenceName="MY_SEQ", allocationSize=1)
如果您愿意,可以让它为您创建序列。但要做到这一点,您必须使用SchemaGeneration来创建它。为此,请使用:
@GeneratedValue(strategy=GenerationType.SEQUENCE)
此外,您可以使用自动生成,它将使用表格生成ID。使用此功能时,您还必须在某些时候使用SchemaGeneration,因此可以创建生成器表。为此,请使用:
@GeneratedValue(strategy=GenerationType.AUTO)
答案 1 :(得分:11)
我使用它并且它正常工作
@Id
@GeneratedValue(generator = "SEC_ODON", strategy = GenerationType.SEQUENCE)
@SequenceGenerator(name = "SEC_ODON", sequenceName = "SO.SEC_ODON",allocationSize=1)
@Column(name="ID_ODON", unique=true, nullable=false, precision=10, scale=0)
public Long getIdOdon() {
return this.idOdon;
}
答案 2 :(得分:7)
即使这个问题很老,我也偶然发现了我自己在JPA 2.0和Oracle序列中遇到的问题。
想要分享我对某些事情的研究 -
数据库序列定义中 GenerationType.SEQUENCE 的 @SequenceGenerator(allocationSize)与 INCREMENT BY 之间的关系
确保将 @SequenceGenerator(allocationSize)设置为与数据库序列定义中的 INCREMENT BY 相同的值,以避免出现问题(同样适用于初始值)。< / p>
例如,如果我们使用INCREMENT BY值20定义数据库中的序列,则将SequenceGenerator中的allocationsize也设置为20.在这种情况下,JPA将不会调用数据库,直到它达到下一个20标记为止它在内部将每个值递增1。这样可以保存数据库调用,以便每次都获取下一个序列号。 这样做的副作用是 - 每当重新部署应用程序或在其间重新启动服务器时,它都会调用数据库以获取下一批,并且您将看到序列值中的跳转。此外,我们需要确保数据库定义和应用程序设置是同步的,这可能无法一直进行,因为它们都由不同的组管理,您很快就会失去控制权。如果数据库值小于allocationsize,则由于Id的重复值,您将看到PrimaryKey约束错误。如果数据库值高于allocationsize,您将看到Id的值跳转。
如果数据库序列INCREMENT BY设置为1(DBA通常会这样做),请将allocationSize设置为1以使它们同步,但JPA每次都调用数据库以获取下一个序列号。
如果您不希望每次都要调用数据库,请使用 GenerationType.IDENTITY 策略并使用数据库触发器设置@Id值。使用 GenerationType.IDENTITY ,只要我们调用 em.persist ,对象就会保存到数据库中,并且将id值赋给返回的对象,因此我们不会必须做 em.merge 或 em.flush 。 (这可能是JPA提供商特定的......不确定)
另一件重要的事情 -
JPA 2.0自动运行 ALTER SEQUENCE 命令,以在数据库序列中同步allocationSize和INCREMENT BY。由于大多数情况下我们使用不同的模式名称(应用程序用户名)而不是序列存在的实际模式,并且应用程序用户名不具有ALTER SEQUENCE权限,因此您可能会在日志中看到以下警告 -
000004c1运行时W CWWJP9991W:openjpa.Runtime:警告:无法使用 缓存序列&#34; RECORD_ID_SEQ&#34;的序列值。您的 应用程序无权运行ALTER SEQUENCE命令。 确保它具有运行ALTER SEQUENCE的适当权限 命令。
由于JPA无法改变序列,JPA每次调用数据库以获取下一个序列号,而不管@ SequenceGenerator.allocationSize的值如何。这可能是我们需要注意的不必要后果。
要让JPA不运行此命令,请在persistence.xml中设置此值。这可确保JPA不会尝试运行ALTER SEQUENCE命令。它写了一个不同的警告 -
00000094运行时W CWWJP9991W:openjpa.Runtime:警告: property&#34; openjpa.jdbc.DBDictionary = disableAlterSeqenceIncrementBy&#34;是 设为true。这意味着&#39; ALTER SEQUENCE ... INCREMENT BY&#39; SQL 语句不会执行序列&#34; RECORD_ID_SEQ&#34;。 OpenJPA的 执行此命令以确保序列的INCREMENT BY值 在数据库中定义的,匹配在其中定义的allocationSize 实体的序列。禁用此SQL语句后,它就是 用户有责任确保实体的顺序 定义与数据库中定义的序列匹配。
正如警告中所述,重要的是我们需要确保数据库序列定义中的@ SequenceGenerator.allocationSize和INCREMENT BY是同步的,包括@SequenceGenerator(allocationSize)的默认值,即50。否则它&#39;会导致错误。
答案 3 :(得分:3)
我有自动化值的MySQL模式。我使用strategy=GenerationType.IDENTITY
标签似乎在MySQL中工作正常我认为它应该适用于大多数数据库引擎。
CREATE TABLE user (
id bigint NOT NULL auto_increment,
name varchar(64) NOT NULL default '',
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
User.java
:
// mark this JavaBean to be JPA scoped class
@Entity
@Table(name="user")
public class User {
@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
private long id; // primary key (autogen surrogate)
@Column(name="name")
private String name;
public long getId() { return id; }
public void setId(long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name=name; }
}
答案 4 :(得分:3)
由于这些问题在使用JPA ad Hibernate时非常常见,因此该答案基于我在博客上写的this article。
现在,回到您的问题:
Q1。此序列生成器是否利用数据库的增量 数值生成能力或在其上生成数字 拥有吗?
通过在GenerationType.SEQUENCE
注释上使用@GeneratedValue
策略,JPA提供程序将尝试使用支持此功能的基础数据库的数据库序列对象(例如,Oracle,SQL Server,PostgreSQL,MariaDB )。
如果您使用的MySQL不支持数据库序列对象,那么Hibernate将转而使用GenerationType.TABLE
,这是不理想的,因为tABELE一代performs badly。
因此,请勿在MySQL中使用GenerationType.SEQUENCE
策略。
第二季度。如果JPA使用数据库自动增量功能,那么它将起作用 没有自动增量功能的数据存储?
我假设您在说GenerationType.IDENTITY
时是在谈论database auto-increment feature
。
要使用AUTO_INCREMENT
或IDENTITY
列,您需要在GenerationType.IDENTITY
注释上使用@GeneratedValue
策略。
Q3。如果JPA自己生成数字值,那么JPA如何 实现知道接下来要生成哪个值?是否咨询 数据库首先查看最后存储了什么值,以便 生成值(最后+1)?
JPA提供程序唯一一次自行生成值的时间是使用基于序列的优化器时,例如:
这些优化器是减少数据库序列调用次数的重要手段,因此它们将使用单个数据库序列调用生成的标识符值的数量相乘。
为避免Hibernate标识符优化器与其他第三方客户端之间发生冲突,应使用pooled
或pooled-lo
而不是hi/lo
。即使您使用的是设计为使用高/低的旧版应用程序,也可以迁移到pooled
或pooled-lo
优化器,如this article中所述。
Q4。还请阐明
sequenceName
和allocationSize
@SequenceGenerator
注释的属性。
sequenceName
属性定义用于生成标识符值的数据库序列对象。它是您使用CREATE SEQUENCE
DDL语句创建的对象。
因此,如果您提供此映射:
@Id
@GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "seq_post"
)
@SequenceGenerator(
name = "seq_post"
)
private Long id;
Hibernate将使用seq_post
数据库对象来生成标识符值:
SELECT nextval('hibernate_sequence')
allocationSize
定义了标识符值乘数,如果您提供的值大于1,则Hibernate将使用pooled
优化器来减少数据库序列调用的次数。 / p>
因此,如果您提供此映射:
@Id
@GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "seq_post"
)
@SequenceGenerator(
name = "seq_post",
allocationSize = 5
)
private Long id;
然后,当您保留5个实体时:
for (int i = 1; i <= 5; i++) {
entityManager.persist(
new Post().setTitle(
String.format(
"High-Performance Java Persistence, Part %d",
i
)
)
);
}
将仅执行2个数据库序列调用,而不是5个:
SELECT nextval('hibernate_sequence')
SELECT nextval('hibernate_sequence')
INSERT INTO post (title, id)
VALUES ('High-Performance Java Persistence, Part 1', 1)
INSERT INTO post (title, id)
VALUES ('High-Performance Java Persistence, Part 2', 2)
INSERT INTO post (title, id)
VALUES ('High-Performance Java Persistence, Part 3', 3)
INSERT INTO post (title, id)
VALUES ('High-Performance Java Persistence, Part 4', 4)
INSERT INTO post (title, id)
VALUES ('High-Performance Java Persistence, Part 5', 5)
查看this article了解更多详细信息。