Hibernate迁移:子类用不同序列时继承父类@Id的注解配置
嘿,这个继承场景下的ID序列配置问题我之前迁移Hibernate项目时刚好碰到过,给你几个适配不同继承策略的方案,你可以根据自己的数据库表结构来选:
方案1:用@MappedSuperclass让子类完全独立配置(最推荐)
这种方式下父类BaseClass只是作为通用属性的载体,不映射为数据库表,每个子类都是独立的实体,各自使用自己的序列生成ID,完全解耦:
首先定义父类(注意用@MappedSuperclass而非@Entity):
@MappedSuperclass public class BaseClass implements BaseEntity { // 这里只定义ID属性,不指定生成策略,交给子类自己配置 private long id; @Override public void setId(long id) { this.id = id; } @Override public long getId() { return id; } // 其他通用属性的getter/setter... }
然后每个子类独立配置自己的序列生成器:
@Entity @Table(name = "USER_TABLE") // 配置专属序列 @SequenceGenerator( name = "USER_SEQ_GENERATOR", sequenceName = "USER_ID_SEQUENCE", // 数据库中实际的序列名 allocationSize = 1 // 要和数据库序列的增量值一致,避免主键冲突 ) public class User extends BaseClass { // 重写ID属性,指定生成策略和自己的序列生成器 @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USER_SEQ_GENERATOR") private long id; // 子类专属属性... }
另一个子类同理:
@Entity @Table(name = "ORDER_TABLE") @SequenceGenerator( name = "ORDER_SEQ_GENERATOR", sequenceName = "ORDER_ID_SEQUENCE", allocationSize = 1 ) public class Order extends BaseClass { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ORDER_SEQ_GENERATOR") private long id; // 子类专属属性... }
方案2:单表继承(InheritanceType.SINGLE_TABLE)场景下的配置
如果你的项目用的是单表继承(所有子类数据存在同一张表,用鉴别器字段区分),可以通过重写ID属性+@AttributeOverride来覆盖父类的序列配置:
首先定义父类实体:
@Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name = "ENTITY_TYPE") // 鉴别器字段,区分不同子类 public class BaseClass implements BaseEntity { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "DEFAULT_SEQ") @SequenceGenerator(name = "DEFAULT_SEQ", sequenceName = "DEFAULT_ID_SEQUENCE") private long id; // 通用属性和方法... }
然后子类重写ID属性,指定自己的序列:
@Entity @DiscriminatorValue("USER") // 鉴别器值 public class User extends BaseClass { // 重写ID,用@AttributeOverride确保映射到同一张表的ID字段 @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USER_SEQ") @SequenceGenerator(name = "USER_SEQ", sequenceName = "USER_ID_SEQUENCE") @AttributeOverride(name = "id", column = @Column(name = "ID")) private long id; // 子类专属属性... }
方案3:Table per Class(每个子类一张表)场景下的配置
这种策略下每个子类有独立的表,包含父类的所有属性,子类同样可以重写ID属性来指定自己的序列:
父类定义:
@Entity @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) public class BaseClass implements BaseEntity { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE) private long id; // 通用属性... }
子类配置:
@Entity @Table(name = "PRODUCT_TABLE") @SequenceGenerator(name = "PRODUCT_SEQ", sequenceName = "PRODUCT_ID_SEQUENCE") public class Product extends BaseClass { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "PRODUCT_SEQ") private long id; // 子类专属属性... }
注意事项
- 确保数据库中已经创建了对应的序列,并且
allocationSize的值和数据库序列的增量值完全一致,否则会出现主键冲突。 - Hibernate 5.2支持
GenerationType.SEQUENCE,如果需要更灵活的配置(比如Oracle序列的起始值),可以用Hibernate特有的@GenericGenerator:
@Id @GeneratedValue(generator = "CUSTOM_SEQ") @GenericGenerator( name = "CUSTOM_SEQ", strategy = "sequence", parameters = { @Parameter(name = "sequence_name", value = "CUSTOM_ID_SEQ"), @Parameter(name = "initial_value", value = "1000"), @Parameter(name = "increment_size", value = "1") } ) private long id;
内容的提问来源于stack exchange,提问作者user1876040
相关产品推荐
相关产品推荐

