PostgreSQL自增主键插入数据报id非空约束异常问题
问题原因
该报错由两层核心问题导致:
- 你手动编写的原生INSERT SQL完全没有走Hibernate的实体持久化流程,实体类上配置的
@GeneratedValue注解不会对原生SQL执行生效。这条SQL没有传入id字段值,一旦数据库层面的id字段没有配置自动生成值的规则,就会直接触发非空约束报错。 - 即使你是调用Hibernate的
save()/persist()方法插入报这个错,也属于GenerationType.AUTO策略对接PostgreSQL的典型适配问题:- Hibernate 5.x及更早版本中,PostgreSQL方言下的AUTO策略默认使用序列
hibernate_sequence生成主键,但Hibernate不会自动在数据库中创建该序列,也不会自动给id字段绑定序列默认值,主键取值失败时就会向数据库插入NULL值触发报错。 - 主键字段使用基本类型
int定义时,未赋值状态下默认值为0,部分场景下会干扰Hibernate对实体临时态的判断,跳过主键生成逻辑。 - 如果建表时没有给id字段配置自增属性、也没有关联序列默认值,数据库本身不具备自动生成主键的能力,任何不传id的插入请求都会失败。
- Hibernate 5.x及更早版本中,PostgreSQL方言下的AUTO策略默认使用序列
解决方案
根据实际场景选择对应方案即可:
- 方案1(生产环境推荐):使用IDENTITY主键策略,匹配PostgreSQL原生自增能力
第一步修改实体类主键配置,注意将基本类型int替换为包装类型Integer,避免默认值干扰:
第二步执行DDL修改表结构,给id字段加自增属性:@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id;
该方案下,无论是走Hibernate持久化方法,还是执行不传id的原生INSERT,数据库都会自动生成递增主键,不会触发非空约束报错。ALTER TABLE public.people ALTER COLUMN id ADD GENERATED ALWAYS AS IDENTITY; - 方案2:保留AUTO策略,补全数据库层面的依赖配置
执行以下DDL创建Hibernate默认依赖的序列,同时给id字段绑定序列默认值:CREATE SEQUENCE IF NOT EXISTS hibernate_sequence START WITH 1 INCREMENT BY 1; ALTER TABLE public.people ALTER COLUMN id SET DEFAULT nextval('hibernate_sequence'); - 临时验证场景:如果只是临时执行手写的INSERT语句,可以手动查询序列下一个值传入id字段,示例:
INSERT INTO public.people (id, name, age) VALUES (nextval('hibernate_sequence'), 'Paul', 12);
内容的提问来源于stack exchange,提问作者Schrumpfpilz
相关产品推荐
相关产品推荐

