JPA @SequenceGenerator注解是如何工作的

wydwbb8l  于 2022-11-14  发布在  其他
关注(0)|答案(6)|浏览(241)

我正在学习JPA,在@SequenceGenerator注解中有困惑。
据我所知,它会自动为实体的数字标识字段/属性分配一个值。

**Q1.**此序列生成器是利用数据库不断增加的数值生成功能还是自己生成数字?
**Q2.**如果JPA使用数据库自动增量功能,那么它是否可以与没有自动增量功能的数据存储一起使用?
**Q3.**如果JPA自己生成数值,那么JPA实现如何知道下一个要生成哪个值?它是否首先查询数据库以查看最后存储的值,以便生成值(last + 1)?
**问题4.**还请说明@SequenceGenerator注解得sequenceNameallocationSize属性.

r1zk6ea1

r1zk6ea11#

sequenceName是数据库中序列的名称。这是您指定数据库中已存在序列的方法。如果使用此方法,则必须指定allocationSize,该值必须与数据库序列用作其“自动增量”的值相同。
用法:

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

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

@GeneratedValue(strategy=GenerationType.SEQUENCE)

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

@GeneratedValue(strategy=GenerationType.AUTO)
clj7thdc

clj7thdc2#

我用这个,它工作正常

@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;
}
7uzetpgm

7uzetpgm3#

尽管这个问题已经很老了,我是因为自己在JPA 2. 0和Oracle序列方面的问题而偶然发现的。
想和大家分享我的研究成果吗-
数据库序列定义中 GenerationType.SEQUENCE@SequenceGenerator(allocationSize)INCREMENT BY 之间的关系
确保将 @SequenceGenerator(allocationSize) 设置为与数据库序列定义中的 INCREMENT BY 相同的值,以避免出现问题(这同样适用于初始值)。
例如,如果我们将数据库中的序列定义为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.mergeem.flush。(这可能是JPA提供程序特定的..不确定)
"另一件重要的事“
JPA 2.0自动运行 ALTER SEQUENCE 命令以同步数据库序列中的allocationSize和INCREMENT BY。由于我们通常使用不同的模式名称(应用程序用户名),而不是序列所在的实际模式,并且应用程序用户名不具有ALTER SEQUENCE权限,因此您可能会在日志中看到以下警告-
000004 c1运行时间W CWWJP 9991 W:openjpa.Runtime:警告:无法缓存序列“RECORD_ID_SEQ”的序列值。您的应用程序没有运行ALTER SEQUENCE命令的权限。请确保它具有运行ALTER SEQUENCE命令的相应权限。
由于JPA无法更改序列,因此JPA每次都会调用数据库以获取下一个序列号,而不考虑@ SequenceGenerator. allocationSize的值。这可能是我们需要注意的不希望出现的结果。
要使JPA不运行此命令,请在persistence.xml中设置此值。这可确保JPA不会尝试运行ALTER SEQUENCE命令。它会写入不同的警告-
00000094运行时间W CWWJP 9991 W:openjpa.Runtime:警告:属性“openjpa.jdbc.DBDictionary=disableAlterSeqenceIncrementBy”设置为true。这意味着不会对序列“RECORD_ID_SEQ”执行'ALTER SEQUENCE... INCREMENT BY' SQL语句。OpenJPA执行此命令以确保数据库中定义的序列的INCREMENT BY值与实体序列中定义的allocationSize匹配。禁用此SQL语句后,用户有责任确保实体的序列定义与数据库中定义的序列相匹配。
如警告中所述,此处重要的是我们需要确保数据库序列定义中的@SequenceGenerator.allocationSize和INCREMENT BY同步,包括@SequenceGenerator(allocationSize)的默认值50。否则将导致错误。

kr98yfug

kr98yfug4#

现在,回到你的问题:
这个序列生成器是利用数据库不断增加的数值生成能力还是自己生成数字?
通过在@GeneratedValue注解上使用GenerationType.SEQUENCE策略,JPA提供程序将尝试使用支持此特性的底层数据库(例如Oracle、SQL Server、PostgreSQL、MariaDB)的数据库序列对象。
如果您使用的是MySQL,它不支持数据库序列对象,那么Hibernate将转而使用GenerationType.TABLE,这是不希望的,因为TABLE生成的性能很差。
因此,不要对MySQL使用GenerationType.SEQUENCE策略。
Q2.如果JPA使用数据库自动增量功能,那么它是否可以与没有自动增量功能的数据存储一起工作?
当你说database auto-increment feature时,我假设你说的是GenerationType.IDENTITY
要使用AUTO_INCREMENTIDENTITY列,需要对@GeneratedValue注解使用GenerationType.IDENTITY策略。
问题3:如果JPA自己生成数值,那么JPA实现如何知道下一个要生成哪个值?它是否首先查询数据库,以查看最后存储的值,从而生成值(last + 1)?
JPA提供程序仅在您使用基于序列的优化器时自己生成值,例如:

这些优化器主要用于减少数据库序列调用的数量,因此它们会增加使用单个数据库序列调用可以生成的标识符值的数量。
为了避免Hibernate标识符优化程序与其他第三方客户端之间的冲突,您应该使用pooledpooled-lo,而不是hi/lo。即使您使用的是设计为使用hi/lo的旧版应用程序,也可以使用migrate to the pooled or pooled-lo optimizers
问题4:请说明@SequenceGenerator注解的sequenceNameallocationSize属性。
sequenceName属性定义用于生成标识符值的数据库序列对象。它是使用CREATE SEQUENCE DDL语句创建的对象。
因此,如果提供以下Map:

@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优化器来减少数据库序列调用的数量。
因此,如果提供以下Map:

@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)
8nuwlpux

8nuwlpux5#

我有MySQL模式与autogen值。我使用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; }
}
whhtz7ly

whhtz7ly6#

我必须在创建一个表后在postgresql上创建一个序列。记住,让spring负责DB序列不是一个好主意。删除@GeneratedValue(strategy=GenerationType.SEQUENCE)
在您的模型上添加

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

并在SQL上运行

CREATE SEQUENCE my_seq
INCREMENT BY 1;

相关问题