flyway迁移后弹簧数据不计算SERIAL列的行数

Posted

技术标签:

【中文标题】flyway迁移后弹簧数据不计算SERIAL列的行数【英文标题】:After flyway migration spring data not counting rows for SERIAL column 【发布时间】:2020-04-29 14:29:57 【问题描述】:

我的迁移工作正常,但在数据库中成功创建迁移并加载测试数据后,我在创建操作时遇到错误。

错误:重复的键值违反了唯一约束“users_pkey” 详细信息:键 (id)=(1) 已存在。

从 SQL spring 数据日志查询:

插入用户(account_non_expired、account_non_locked、 credentials_non_expired,启用,密码,用户名)值(?,?,?, ?, ?, ?)

在迁移中,我将几个测试用户设置到表中,但休眠时没有注意到它并尝试将行作为第一个写入。

我的users 表:

CREATE TABLE IF NOT EXISTS users
(
    id                      BIGSERIAL PRIMARY KEY,
    username                VARCHAR(255) UNIQUE NOT NULL,
    password                VARCHAR(255)        NOT NULL,
    account_non_expired     BOOLEAN DEFAULT TRUE,
    account_non_locked      BOOLEAN DEFAULT TRUE,
    credentials_non_expired BOOLEAN DEFAULT TRUE,
    enabled                 BOOLEAN DEFAULT TRUE
);

实体类:

@Data
@Entity
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "users")
@EqualsAndHashCode(exclude = "roles")
@ToString(exclude = "roles")
public class User 

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "username")
    private String username;

    @Column(name = "password")
    private String password;

    @Column(name = "account_non_expired")
    private Boolean accountNonExpired;

    @Column(name = "account_non_locked")
    private Boolean accountNonLocked;

    @Column(name = "credentials_non_expired")
    private Boolean credentialsNonExpired;

    @Column(name = "enabled")
    private Boolean enabled;

    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(name = "users_roles",
            joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"),
            inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id"))
    private List<Role> roles;

实际上策略GenerationType.IDENTITYBIGSERIAL 一起工作,当我在增量后发送请求 3 次时,我保持在正确的位置。每个对 DB Hibernate 的请求都会使 +1。

本用户数据迁移:

INSERT INTO users (id, username, password)
VALUES (1, 'user', 'pass'),
       (2, 'operator', 'pass'),
       (3, 'admin', 'pass');

如何解决,让Hibernate能注意到数据从开始的数据量?

【问题讨论】:

一个 bigserial 列由一个序列支持:postgresql.org/docs/12/datatype-numeric.html#DATATYPE-SERIAL。由于您在飞行路径迁移中插入值而没有从该序列中获取 ID,因此该序列中的下一个值将保持在原处。因此,当 Hibernate 通过让数据库生成一个 ID 来插入一个值时,该序列会给出一个已经使用过的 ID。所以你需要在插入数据后设置序列的值。在postgresql.org/docs/12/sql-createsequence.html中寻找setval @JB Nizet 如果我摆脱在迁移中直接设置 ID 的意思。解决问题了吗? 是的,应该。 【参考方案1】:

为您的 id 创建一个序列:

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USER_SEQ")
    @SequenceGenerator(name = "USER_SEQ", sequenceName = "USER_SEQ", allocationSize = 1)
    private Long id;

像这样创建您的 SQL 文件:

INSERT INTO users (id, username, password)
VALUES (NEXTVAL('USER_SEQ'), 'user', 'pass'),
       (NEXTVAL('USER_SEQ'), 'operator', 'pass'),
       (NEXTVAL('USER_SEQ'), 'admin', 'pass');

“users”表的顺序应该会自动更新。

【讨论】:

【参考方案2】:

添加到迁移SELECT setval('users_id_seq', 4);

INSERT INTO users (id, username, password)
VALUES (1, 'user', 'pass'),
       (2, 'operator', 'pass'),
       (3, 'admin', 'pass');

SELECT setval('users_id_seq', 4);

这解决了序列状态与实际行数之间的冲突。

【讨论】:

它适用于数据库初始化,但我认为当应用程序“生活”在生产中时,它不是一个可行的解决方案。那么,在插入数据之前检索然后更新实际序列的任何想法?

以上是关于flyway迁移后弹簧数据不计算SERIAL列的行数的主要内容,如果未能解决你的问题,请参考以下文章

如何在某个弹簧配置文件中禁用飞路?

最佳实践:使用后如何修改flyway迁移脚本

如何回滚 Flyway Scala 中的迁移?

清洁后无法启动或迁移的flyway

如何应对不断变化的 Flyway 迁移?

手动更改表中的varchar大小后如何同步Flyway迁移文件?