Spring Boot初始化PostgreSQL数据库数据时触发id列非空约束错误
嘿,我来帮你搞定这个问题!你遇到的错误根源其实和UUID的生成方式有关——你的实体类里是让Hibernate来生成UUID值,而非让PostgreSQL数据库自己处理,所以在data.sql里写DEFAULT时,数据库不知道该怎么生成这个id,自然就抛出非空约束的错误了。
问题原因拆解
你的PlantVocEntity的id字段用了@GeneratedValue(strategy = GenerationType.UUID),这个策略是让Hibernate在持久化实体时自动生成UUID,并不会让PostgreSQL为该列设置默认生成逻辑。当你直接用SQL插入数据时,写DEFAULT相当于告诉数据库“用列的默认值”,但这个列根本没有数据库层面的默认值,所以就插入了null,触发了非空约束。
可行的解决方案
方案一:手动指定UUID值插入
直接在INSERT语句的VALUES里填写一个合法的UUID字符串就行,比如:
INSERT INTO plants_voc ( id, ipni, full_name_plain, full_name_no_authors_plain, plant_name, family, genus, species, valid_nomenclature, rank, leaf_habitus, created_datetime_utc, updated_datetime_utc ) VALUES ( '123e4567-e89b-12d3-a456-426614174000', -- 手动生成的合法UUID 'urn:lsid:ipni.org:names:294902-1', 'Alnus cordata (Loisel.) Duby', 'Alnus cordata', 'cordata', 'Betulaceae', 'Alnus', 'cordata', TRUE, 'SPECIES', 'DECIDUOUS', NOW(), NOW() );
你可以在PostgreSQL的命令行里执行SELECT uuid_generate_v4();来生成可用的UUID,或者用在线UUID生成工具也行。另外要注意,如果你开启了spring.sql.init.mode=always,每次启动都会执行这个SQL,为了避免主键冲突,可以加上ON CONFLICT (id) DO NOTHING。
方案二:修改实体类,让PostgreSQL自动生成UUID
这种方式让数据库负责UUID的生成,步骤如下:
- 先确保PostgreSQL启用了
uuid-ossp扩展(用来生成UUID的官方工具),可以在schema.sql里添加这条语句:
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
- 修改
PlantVocEntity的id字段注解,添加columnDefinition来指定数据库列的默认值:
@Id @GeneratedValue(strategy = GenerationType.UUID) @Column(name="id", length = 50, nullable = false, updatable = false, columnDefinition = "uuid DEFAULT uuid_generate_v4()") private UUID id;
这样Hibernate创建表时,会给id列设置默认值为uuid_generate_v4(),之后你在data.sql里用DEFAULT插入,数据库就会自动生成UUID值了。
额外提醒
你的配置里spring.jpa.hibernate.ddl-auto=create,每次启动都会重新创建表,所以修改实体类的注解后,重启应用就能生效。如果之后不想每次都重建表,可以把这个参数改成update或者none,配合schema.sql和data.sql来管理数据库结构。
备注:内容来源于stack exchange,提问作者Gianni Spear

