Spring Boot中schema.sql与Hibernate冲突导致唯一约束报错问题
问题根因
出现主键冲突是三层逻辑不同步导致的:
- 配置了
spring.jpa.defer-datasource-initialization=true时,执行顺序为:Hibernate初始化(执行ddl-auto=update逻辑) -> 执行schema.sql脚本 -> 执行data.sql脚本。你在schema.sql里会先删除EMPLOYEE表再重建,等于Hibernate初始化阶段拿到的表结构信息、维护的主键序列计数,在脚本执行后完全失效。 - 实体类主键用了
GenerationType.AUTO策略,在H2数据库下Hibernate会默认独立维护主键生成序列,不会主动读取表本身AUTO_INCREMENT字段的当前偏移值。 - 你通过
data.sql插入了id=1的初始员工数据(报错信息里的RAGHU就是这条数据),但Hibernate不知道这条数据存在,第一次插入新数据时仍然生成id=1,直接和已有数据主键撞车。
修复方案
选择任意一种方案即可,优先推荐前两种组合使用:
方案1:关闭Hibernate自动DDL,完全由SQL脚本管理表结构
既然你已经用schema.sql和data.sql管理表结构和初始数据,就不需要Hibernate再做表结构同步,修改application.properties配置:
# 把原配置的update改为none spring.jpa.hibernate.ddl-auto=none
改完后启动顺序就不会出现Hibernate建表又被脚本删除重建的混乱问题。
方案2:对齐实体主键生成策略和表结构
你建表时用的是数据库层面的AUTO_INCREMENT自增主键,对应把实体类的主键生成策略改为IDENTITY,让Hibernate插入数据时直接依赖数据库自增字段的计数,不要自己独立维护序列:
@Entity @Getter @Setter @NoArgsConstructor public class Employee { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; // 其余字段保持原有逻辑不变 }
改完后Hibernate插入新数据时,会自动读取EMPLOYEE表当前AUTO_INCREMENT的起始值,你初始插入了id=1的数据,表自增偏移会自动跳到2,后续插入不会再出现主键冲突。
方案3:手动校准表自增起始值
如果不想调整实体类配置,也可以在schema.sql末尾追加SQL,手动把表的自增起始值设为比初始数据最大id大的数值,比如你初始插入了1条id=1的数据,就加一行:
ALTER TABLE EMPLOYEE ALTER COLUMN ID RESTART WITH 2;
如果后续初始数据加了更多条,对应调整RESTART WITH后面的数值即可。
额外建议:写
data.sql插入初始数据时,尽量不要手动指定ID字段的值,直接写INSERT INTO EMPLOYEE(NAME, SALARY, LAST_UPDATE) VALUES ('RAGHU', 250.1, '2022-04-23 00:00:00'),让数据库自动生成自增ID,从根源避免自增序列和插入数据ID不匹配的问题。
内容的提问来源于stack exchange,提问作者sonic boom
相关产品推荐
相关产品推荐

