Spring Boot JPA:如何让继承BaseEntity的各实体objectId独立自增
问题描述
我定义了一个抽象类BaseEntity,用于封装项目中多个实体类的共享字段,代码如下:
@MappedSuperclass @AllArgsConstructor @NoArgsConstructor @Data public abstract class BaseEntity { @Id @Column(name = "objectId", insertable = false, updatable = false) @GeneratedValue(strategy = GenerationType.AUTO) private long objectId; @Column(name = "createdDate", updatable = false/*, columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP"*/) @CreationTimestamp private Date createdDate; @Column(name = "updatedDate"/*, columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP"*/) @UpdateTimestamp private Date updatedDate; @Column(name = "active", columnDefinition = "boolean default false") private boolean active; }
多个实体类(比如User和Contact)继承自该BaseEntity,但保存实体时发现objectId是全局递增的:保存User后其objectId为1,保存Contact后其objectId为2。请问如何让每个实体的objectId字段各自独立递增?
解决方案
出现全局递增的核心原因是GenerationType.AUTO会让JPA根据数据库类型自动选择ID生成策略,多数场景下会复用全局共享的序列或生成表,导致所有继承实体共用同一个ID生成源。以下是几种实现每个实体ID独立递增的可行方案:
方法1:使用IDENTITY策略(适配MySQL、SQL Server等支持自增列的数据库)
修改BaseEntity中的@GeneratedValue注解,将策略改为IDENTITY,同时确保数据库中每个实体对应表的objectId字段设置为自增列:
@Id @Column(name = "objectId", insertable = false, updatable = false) @GeneratedValue(strategy = GenerationType.IDENTITY) private long objectId;
注意:MySQL中需将表的objectId字段定义为BIGINT AUTO_INCREMENT PRIMARY KEY,这样每个表会维护独立的自增计数器,实现ID单独递增。
方法2:为每个实体单独配置序列生成器(适配Oracle、PostgreSQL等支持序列的数据库)
由于@MappedSuperclass中的序列生成器会被子类共享,需要在每个子类中单独定义专属的序列生成器:
- 先调整
BaseEntity中的@GeneratedValue,不指定固定生成器,留空让子类覆盖:
@Id @Column(name = "objectId", insertable = false, updatable = false) @GeneratedValue private long objectId;
- 在
User实体中定义专属序列:
@Entity @SequenceGenerator(name = "user_seq", sequenceName = "user_object_id_seq", allocationSize = 1) public class User extends BaseEntity { // 实体专属字段... }
- 在
Contact实体中定义另一组序列:
@Entity @SequenceGenerator(name = "contact_seq", sequenceName = "contact_object_id_seq", allocationSize = 1) public class Contact extends BaseEntity { // 实体专属字段... }
说明:每个序列对应数据库中的独立序列对象,各自维护递增计数器,完全实现ID独立。
方法3:使用TABLE策略并为每个实体指定区分标识(跨数据库兼容方案)
如果需要适配多种数据库,可使用TABLE策略,通过统一的ID生成表存储不同实体的计数器,用标识字段区分:
- 调整
BaseEntity中的@GeneratedValue:
@Id @Column(name = "objectId", insertable = false, updatable = false) @GeneratedValue(strategy = GenerationType.TABLE) private long objectId;
- 在
User实体中定义专属表生成器:
@Entity @TableGenerator( name = "user_id_generator", table = "id_generators", pkColumnName = "entity_type", valueColumnName = "next_id", pkColumnValue = "USER", allocationSize = 1 ) public class User extends BaseEntity { // 实体专属字段... }
- 在
Contact实体中定义另一组表生成器:
@Entity @TableGenerator( name = "contact_id_generator", table = "id_generators", pkColumnName = "entity_type", valueColumnName = "next_id", pkColumnValue = "CONTACT", allocationSize = 1 ) public class Contact extends BaseEntity { // 实体专属字段... }
说明:这种方式通过pkColumnValue区分不同实体的计数器,既实现ID独立,又能在不同数据库环境下兼容运行。
内容的提问来源于stack exchange,提问作者Itzik.B
相关产品推荐
相关产品推荐

