您的位置:首页 > 其它

HIbernate继承映射策略

2016-06-10 13:12 375 查看
策略选择:

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同理。
//当尝试获取代理的具体方法是会具体命中数据库,底层调用具体类型来实现。


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  hibernate