JPA如何配置实现数据库ID支持客户端与服务端双端生成?
JPA 实现客户端与服务端双端ID生成的适配方案
现有配置的问题根源
你当前使用的SEQUENCE ID生成策略,本质是JPA应用侧驱动的取值流程:
- 执行插入操作前,JPA会先单独发起一次查询,从绑定的数据库序列
my_seq中拿到下一个可用ID值 - 把拿到的ID显式填充到实体对象中,再携带这个明确的ID值执行INSERT语句
整个插入过程完全不依赖数据库表列的默认自动生成规则,因此JPA自动生成表结构时,只会将ID列定义为普通的bigint类型主键,不会附加任何自动生成属性。这也是为什么直接用数据库工具手动插入数据时,因为既没有传入ID值,列本身也没有自动取值规则,就会触发非空约束报错。
可落地的双端适配方案
要同时满足「JPA应用正常运行、绕过应用直接写库时也能自动生成ID」的需求,可以根据业务场景选择以下两种方案:
方案1:保留原SEQUENCE策略,为ID列绑定序列默认值
该方案完全不改动现有Java侧的ID生成逻辑,只需要在数据库侧做少量适配,适合需要提前拿到ID值(比如插入主表后要预先关联子表外键)的场景:
- 确认当前使用的MariaDB版本≥10.3,该版本开始原生支持序列对象、以及列默认值绑定序列取值的语法
- JPA自动建好表和序列
my_seq后,执行一次列定义修改语句,把ID列的默认值绑定到序列的下一个取值:ALTER TABLE 目标业务表 MODIFY COLUMN id BIGINT NOT NULL DEFAULT (NEXT VALUE FOR my_seq); - 如果不想手动执行DDL语句,也可以在实体类的ID字段上补充列定义配置,让JPA自动建表时就带上这个默认规则:
@Id @SequenceGenerator(name = "my_sequence", sequenceName = "my_seq") @GeneratedValue(generator = "my_sequence", strategy = GenerationType.SEQUENCE) @Column(columnDefinition = "BIGINT NOT NULL DEFAULT (NEXT VALUE FOR my_seq)") private long id;
配置完成后,两侧的运行逻辑完全兼容:
- JPA应用侧仍沿用原有的序列取值逻辑,运行行为和之前完全一致,不受任何影响
- 直接通过数据库工具、其他非JPA程序插入数据时,如果没有显式传入ID值,数据库会自动从
my_seq序列中取值填充,不会触发非空报错
方案2:切换为IDENTITY自增列策略
如果业务场景不需要在插入前预先拿到ID值,只要双端能自动生成合法ID即可,直接换用MariaDB原生的自增列策略,适配成本更低:
- 修改实体类的ID注解配置,替换原有序列相关的注解:
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; - 该配置下JPA自动建表时,会直接将ID列定义为
BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,实现效果:- JPA应用执行插入时,会发送不带ID值的INSERT语句,由数据库自动生成自增ID,插入完成后再将生成的ID回填到实体对象中
- 直接通过数据库工具、其他程序插入数据时,数据库的自增规则会自动生成连续的合法ID,不会出现空值约束报错
注意:IDENTITY策略的局限是,JPA无法在执行INSERT前预先拿到ID值,如果业务逻辑需要在插入主表前就绑定ID作为子表的外键关联值,这种场景就不适合用该方案
内容的提问来源于stack exchange,提问作者Dims
相关产品推荐
相关产品推荐

