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.IDENTITY
与BIGSERIAL
一起工作,当我在增量后发送请求 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列的行数的主要内容,如果未能解决你的问题,请参考以下文章