HIbernate继承映射策略

来源:互联网 发布:月数据分析报告模板 编辑:程序博客网 时间:2024/03/29 02:31
  • 策略选择:
    1)不需要多态关联以及从父类查询时,使用@MappedSuperclass/TABLE_PER_CLASS,偏向于TABLE_PER_CLASS,因为万一有少量需要关联、查询可以在牺牲性能的前提下满足(使用union)。
    2)当需要多态以及从父类查询(较多),而且子类较父类的属性变化不大(新增实例域少),可以考虑使用SINGLE_TABLE。
    3)当需要多态以及从父类查询(较多),而且子类较父类的属性变化较大(新增实例域多),此时若使用SINGLE_TABLE则造成较多的数据不完整(null)以及范式违反,所以使用TABLE_PER_CLASS/JOINED,具体选择决定于子类的数量(子类多则连接的性能降低),比较性能。

  • 每个具体子类一张表,各有各的id。即直接继承父类的属性到子类中

//在父类中使用@MappedSuperclass,每个子类有自己的id(可以继承父类的生成策略与主键名)//缺点是不存在多态关联(id冲突导致),但是只用于拓展父类属性时很实用,一般用于高层次的类(高层类一般不需要多态关联)@MappedSuperclasspublic abstract class Father{    private String familyName;}@Entity@Table(name="son1")//重写父类属性@AttributeOverrides()public class Son1 extends Father{    @Id    @GeneratedValue    private long id;    ...}...write Son2...

//以下三种策略,id都必须在父类中定义,最好为protected。
* 每个具体子类一张表,共享主键,select * from Father时,则执行一个union子查询,支持动态绑定以及多态关联,缺点是执行子查询时需要加载所有的子表所以性能较差(如果使用下一个可以直接使用索引快速查找)。

//在父类中使用@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS),在子类中不再配置id,只注解@Entity即可,使得Other -> Father 的关联成为可能@Entity@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)public abstract class Father{    @Id    @GeneratedValue    protected long id;    private String familyName;}//仍旧需要@Entity@Entitypublic class Son1 extends Father1{}//union子查询示例select        father0_.id as id1_0_0_,        father0_.s1 as s1_1_0_,        father0_.s2 as s1_2_0_,        father0_.clazz_ as clazz_0_     from        ( select            id,            s1,            null as s2,            1 as clazz_         from            Son1         union        select            id,            null as s1,            s2,            2 as clazz_         from            Son2     ) father0_ where    father0_.id=?
  • 所有的类使用一张表,共享主键,支持多态以及关联,由于一般情况下的最佳选择,但违反第三范式以及数据不够完整(很多null),由于不需要union操作,可以充分利用索引,其性能上优于方式二,性能比较见文末截图。
//父类使用@Inheritance(strategy = InheritanceType.SINGLE_TABLE),并用@DiscriminatorColumn(name = "BD_TYPE")@Entity指定区别不同子类的列名@Inheritance(strategy = InheritanceType.SINGLE_TABLE)@DiscriminatorColumn(name = "BD_TYPE")public abstract class Father{    @Id    @GeneratedValue    protected long id;    private String familyName;}//子类使用@Entity//指定具体的子类列值,用于多态转换提取数据@DiscriminatorValue("Son1")public class Son1 extends Father{    ...}
  • 每个子类一张表,使用连接查询,每个子类使用到父类的外键关联作为主键关联,支持多态与关联,简单但效率较三低。
//父类中使用@Inheritance(strategy = InheritanceType.JOINED)@Entity@Inheritance(strategy = InheritanceType.JOINED)public abstract class Father {    @Id    @GeneratedValue    protected long id;    ...   }//在子类中可以指定引用自父类的外键名(也是该子类的主键)@@Entity@PrimaryKeyJoinColumn(name = "CREDITCARD_ID")public class Son1 extends Father {    ...}//实际执行 selct * from Father的过程使用join实现,具体如下select        father0_.id as id1_0_0_,        father0_1_.s1 as s1_1_0_,        father0_2_.s2 as s1_2_0_,        case             when father0_1_.id is not null then 1             when father0_2_.id is not null then 2             when father0_.id is not null then 0         end as clazz_0_     from        Father father0_     left outer join        Son1 father0_1_             on father0_.id=father0_1_.id     left outer join        Son2 father0_2_             on father0_.id=father0_2_.id     where        father0_.id=?
  • 一个嵌入式类不能使用多态以及关联,所以只有@MappedSuperClass这一策略
  • 多态与代理。
//使用get(X.class,yy),总是直接命中数据库,返回准确的实现对象//使用load(X.class,yy),则总是尝试返回X.class的一个代理,所以尝试对load返回的对象进行子类型强转(具体映射到数据库的类型)会出现错误。//当Fetch配置为lazy时,总是尝试返回代理,与load同理。//当尝试获取代理的具体方法是会具体命中数据库,底层调用具体类型来实现。

0 0