下面是一个简单的例子: 使用的数据库是 PostgresSQL。使用的堆栈:Spring Boot + Hibernate + FlyWay
@数据
@Entity
@Table(name = "books")
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long bookId;
//....
}
这是hibernate生成的表
create table if not exists books
(
book_id bigserial not null
constraint books_pkey
primary key,
language_id bigint
constraint fksp7ty25kndaxyfrgkrloo1dd8
references author
);
用于导入的 sql 查询示例:
INSERT INTO "public"."books" ("book_id", "author_id") VALUES (1, 2);
通过flyway序列的数据迁移后未更新。那些。我应该有超过 200 个对象,并且序列索引显示 1。
SELECT last_value FROM books_book_id_seq;
last_value 0
在这种情况下,例如,对于由 java 脚本初始化的另一个实体,索引会正确显示。问题与此类似: 链接
如果 GenerationType.IDENTITY ,为什么休眠会生成序列?我的错误是什么?
更新
尝试了其他方法 - 更改了 GenerationType.SEQUENCE hibernate created hibernate_sequence 但也将表 DDL 更改为(bigserial -> bigint):
create table if not exists books
(
book_id bigint not null
constraint books_pkey
primary key,
language_id bigint
constraint fksp7ty25kndaxyfrgkrloo1dd8
references author
);
在任何情况下,当通过 flyway 迁移时,该值都不会增加。我可以手动更正此值的最大值。
好吧,既然序列中的值不正确,那么这里就是异常——DataIntegrityViolationException
提前感谢您的回复!
这里对
serial
/bigserial
type 如何在postgres
.如果您在创建条目时未指定值,这种类型将从
sequence
. 如果该字段的值是显式设置的(就像您创建的迁移一样),那么它会按原样插入,并且不会修改序列。您可以通过以下三种方式之一解决此问题。在迁移中创建条目时,您可以:
book_id
自动生成机制工作sequence
绑定到字段book_id
sequence
插入所有记录后手动更新考虑这些选项
不要指定 book_id
如果需要引用新生成的标识符,可以这样(使用作者的例子):
手动使用序列
老实说,该选项没有多大意义,但为了完整起见,我也将其包括在内。请求将如下所示:
插入所有记录后手动更新序列
这里不完全正确。
sequence
创建 nothibernate
,但是postgres
。IDENTITY
表示如果不设置该字段将由数据库自动生成。那些。hibernate
在数据库中创建新实体时,它根本不传递此字段。自动生成值是数据库的责任。在
postgres
具有自动生成值的类型中 -serial
/bigserial
。里面用到sequence
的是一个自动生成的实现细节postgres
(毕竟它是自动创建的,大部分情况下用户不需要管它——字段是自动生成的,这是需要的)。这就是为什么这个sequence
没有出现在映射中的任何地方hibernate
。并且
GenerationType.SEQUENCE
您需要在映射中明确指定使用哪一个sequence
。创建新记录时,hibernate
它将使用配置中指定的字段查询数据库以生成该字段的值sequence
。然后在执行的时候直接使用这个值INSERT
。当您将生成器类型更改为 时
GenerationType.SEQUENCE
,在这种情况下,它hibernate
会在数据库中创建另一种类型的字段 -bigint
,即 没有自动生成的类型,因为您明确告诉使用sequence
.