HIbernate继承映射策略

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

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

//在父类中使用@MappedSuperclass,每个子类有自己的id(可以继承父类的生成策略与主键名)
//缺点是不存在多态关联(id冲突导致),但是只用于拓展父类属性时很实用,一般用于高层次的类(高层类一般不需要多态关联)
@MappedSuperclass
public 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
@Entity
public 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同理。
//当尝试获取代理的具体方法是会具体命中数据库,底层调用具体类型来实现。

763939-20160404175706765-1251508797.png

转载于:https://www.cnblogs.com/fcat/p/5352465.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值