hibernate支援三種繼承映射政策:
使用subclass進行映射
将域模型中的每一個實體對象映射到一個獨立的表中,也就是說不用在關系資料模型中考慮域模型中的繼承和多态。
使用joined-subclass進行映射
對于繼承關系中的子類使用通一個表,這就是需要在資料庫表中增加額外的區分子類類型的字段。
使用union-subclass進行映射
域模型中的每個類型映射到一個表,通過關系資料模型中的外鍵來描述表之間的繼承關系。
這也就相當于按照域模型的結構來建立關系資料庫中的表,并通過外鍵來建立表之間的繼承關系。
1.使用subclass進行映射
将域模型中的每一個實體對象映射到一個獨立的表中,也就是說不用在關系資料模型中考慮域模型中的繼承和多态。
person父類
public class Person {
private Integer id;
private String name;
private int age;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
學生子類
public class Student extends Person {
private String school;
public String getSchool() {
return school;
}
public void setSchool(String school) {
this.school = school;
}
}
這裡隻需要一個person類的hbm映射檔案
映射檔案中需要添加對應的映射,該模型中隻需要添加一個映射檔案,因為隻生成一張表,
在映射檔案中添加對應的子類映射,使用subclass标簽,标簽中添加鑒别器discriminator-value,
該鑒别器屬性指明了在資料庫中寫入資料時訓示寫入的是何種類型
<hibernate-mapping package="com.mamh.hibernate.demo.entities">
<class name="Person" table="hb_person" schema="mage" discriminator-value="person">
<id name="id">
<column name="hb_id"/>
<generator class="native"/>
</id>
<discriminator type="java.lang.String" column="type"/>
<property name="name" type="java.lang.String">
<column name="hb_name"/>
</property>
<property name="age" type="int">
<column name="hb_age"/>
</property>
<!--映射子類 使用subclass-->
<subclass name="Student" discriminator-value="student">
<property name="school" type="java.lang.String">
<column name="hb_school"/>
</property>
</subclass>
</class>
</hibernate-mapping>
插入操作
@Test
public void testSavePerson(){
//插入操作對于子類對象隻需包記錄擦人到一張表中。
// 辨識者列由hibernate自動維護。
Person person = new Person();
person.setAge();
person.setName("pppp");
Student student = new Student() ;
student.setSchool("zz");
student.setAge();
student.setName("sss");
session.save(person);
session.save(student);
}
Hibernate:
insert
into
mage.hb_person
(hb_name, hb_age, type)
values
(?, ?, 'person')
Hibernate:
insert
into
mage.hb_person
(hb_name, hb_age, hb_school, type)
values
(?, ?, ?, 'student')
=destroy=
Process finished with exit code
對于插入操作,隻需要把記錄插入到一張資料表中。辨識者列由hibernate自動維護。
# | hb_id | type | hb_name | hb_age | hb_school |
---|---|---|---|---|---|
1 | 1 | person | pppp | 18 | NULL |
2 | 2 | student | sss | 128 | zz |
3 | 3 | person | pppp | 18 | NULL |
4 | 4 | student | sss | 128 | zz |
5 | 5 | person | pppp | 18 | NULL |
6 | 6 | student | sss | 128 | zz |
查詢操作
@Test
public void testGetPerson(){
List person = session.createQuery("from Person ").list();
System.out.println(person);
List student = session.createQuery("from Student ").list();
System.out.println(student);
}
查詢操作:父類記錄,隻需要一張資料表。對于子類記錄,也隻需要一張資料表,自動的給加上type=“student”
Hibernate:
select
person0_.hb_id as hb1_9_,
person0_.hb_name as hb3_9_,
person0_.hb_age as hb4_9_,
person0_.hb_school as hb5_9_,
person0_.type as type9_
from
mage.hb_person person0_
[
Person{id=, name='pppp', age=},
Person{id=, name='sss', age=},
Person{id=, name='pppp', age=},
Person{id=, name='sss', age=}
]
Hibernate:
select
student0_.hb_id as hb1_9_,
student0_.hb_name as hb3_9_,
student0_.hb_age as hb4_9_,
student0_.hb_school as hb5_9_
from
mage.hb_person student0_
where
student0_.type='student'
[
Person{id=, name='sss', age=},
Person{id=, name='sss', age=}
]
=destroy=
Process finished with exit code
查詢student子類的時候我們可以看到 其中的sql語句是有個student0_.type=’student’這個條件的。
這個type這一列就是辨識者列。
缺點:
使用了辨識者列。
子類獨有的字段不能添加非空限制。
若繼承層次較深,則資料表的字段也會比較多。
2.使用joined-subclass進行映射
對于繼承關系中的子類使用通一個表,這就是需要在資料庫表中增加額外的區分子類類型的字段。
采用joined-subclass元素的繼承映射可以實作每個子類一張表。
采用這種映射政策時,父類執行個體儲存在父類表中,子類執行個體有父類表和子類表共同存儲。
因為子類執行個體也是一個特殊的父類執行個體,是以也包含了父類執行個體的屬性,于是将子類和父類共有的
屬性儲存在父類表中,子類獨有的屬性則儲存在子類表中。
在這種映射政策下,無需使用鑒别者列,但需要為每個子類使用key元素映射共有主鍵。
子類增加的屬性可以添加非空限制,因為子類的屬性和父類的屬性沒有儲存在同一個表中。
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.mamh.hibernate.demo.entities">
<class name="Person" table="hb_person" schema="mage" >
<id name="id">
<column name="hb_id"/>
<generator class="native"/>
</id>
<property name="name" type="java.lang.String">
<column name="hb_name"/>
</property>
<property name="age" type="int">
<column name="hb_age"/>
</property>
<joined-subclass name="Student" table="hb_student">
<key column="hb_id"></key>
<property name="school" type="java.lang.String">
<column name="hb_school"/>
</property>
</joined-subclass>
</class>
</hibernate-mapping>
儲存操作
@Test
public void testSavePerson(){
//插入操作對于子類對象隻需包記錄擦人到一張表中。
// 辨識者列由hibernate自動維護。
Person person = new Person();
person.setAge();
person.setName("pppp");
Student student = new Student() ;
student.setSchool("zz");
student.setAge();
student.setName("sss");
session.save(person);
session.save(student);
}
Hibernate:
insert
into
mage.hb_person
(hb_name, hb_age)
values
(?, ?)
Hibernate:
insert
into
mage.hb_person
(hb_name, hb_age)
values
(?, ?)
Hibernate:
insert
into
hb_student
(hb_school, hb_id)
values
(?, ?)
=destroy=
Process finished with exit code
person表格
person表格 | hb_id | hb_name | hb_age |
---|---|---|---|
1 | 1 | pppp | 18 |
2 | 2 | sss | 128 |
student表格
student表格 | hb_id | hb_school |
---|---|---|
1 | 2 | zz |
查詢操作
@Test
public void testGetPerson(){
List person = session.createQuery("from Person ").list();
System.out.println(person);
List student = session.createQuery("from Student ").list();
System.out.println(student);
}
Hibernate:
select
person0_.hb_id as hb1_9_,
person0_.hb_name as hb2_9_,
person0_.hb_age as hb3_9_,
person0_1_.hb_school as hb2_10_,
case
when person0_1_.hb_id is not null then
when person0_.hb_id is not null then
end as clazz_
from
mage.hb_person person0_
left outer join
hb_student person0_1_
on person0_.hb_id=person0_1_.hb_id
[Person{id=, name='sss', age=}, Person{id=, name='pppp', age=}]
Hibernate:
select
student0_.hb_id as hb1_9_,
student0_1_.hb_name as hb2_9_,
student0_1_.hb_age as hb3_9_,
student0_.hb_school as hb2_10_
from
hb_student student0_
inner join
mage.hb_person student0_1_
on student0_.hb_id=student0_1_.hb_id
[Person{id=, name='sss', age=}]
=destroy=
Process finished with exit code
優點:
不需要使用鑒别者列
子類獨有的字段能添加非空限制
沒有備援的字段
3.使用union-subclass進行映射
域模型中的每個類型映射到一個表,通過關系資料模型中的外鍵來描述表之間的繼承關系。
這也就相當于按照域模型的結構來建立關系資料庫中的表,并通過外鍵來建立表之間的繼承關系。
采用union-subclass元素可以實作将每一個實體對象映射到一個獨立的表中。
子類增加的屬性可以有非空限制,即父類執行個體的資料儲存在父類表中,而子類執行個體的資料儲存在子類表中。
子類執行個體的資料僅儲存在子類表中,而在父類表中沒有任何記錄
在這種映射政策下,子類表的字段會比父類表的映射字段要多,因為子類表的字段等于父類表的字段,
加子類增加屬性的總和。
在這種政策下,既不需要使用鑒别者列,也無需使用key元素來映射共有主鍵。
使用union-subclass映射政策是不可以使用identity的主鍵生成政策的,因為同一類繼承層次中所有實體類
都需要使用同一個主鍵種子,即多個持久化實體對應的記錄的主鍵應該是連續的,受此影響,
也不該使用native主鍵生成政策,應為native會根據資料庫來選擇使用identity或sequence。
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.mamh.hibernate.demo.entities">
<class name="Person" table="hb_person" schema="mage" >
<id name="id">
<column name="hb_id"/>
<generator class="hilo"/>
</id>
<property name="name" type="java.lang.String">
<column name="hb_name"/>
</property>
<property name="age" type="int">
<column name="hb_age"/>
</property>
<union-subclass name="Student" table="hb_student">
<property name="school" type="java.lang.String">
<column name="hb_school"/>
</property>
</union-subclass>
</class>
</hibernate-mapping>
插入操作
@Test
public void testSavePerson(){
//插入操作對于子類對象隻需包記錄擦人到一張表中。
// 辨識者列由hibernate自動維護。
Person person = new Person();
person.setAge();
person.setName("pppp");
Student student = new Student() ;
student.setSchool("zz");
student.setAge();
student.setName("sss");
session.save(person);
session.save(student);
}
Hibernate:
select
next_hi
from
hibernate_unique_key for update
Hibernate:
update
hibernate_unique_key
set
next_hi = ?
where
next_hi = ?
=destroy=
Hibernate:
insert
into
mage.hb_person
(hb_name, hb_age, hb_id)
values
(?, ?, ?)
Hibernate:
insert
into
hb_student
(hb_name, hb_age, hb_school, hb_id)
values
(?, ?, ?, ?)
Process finished with exit code
父類person表 | hb_id | hb_name | hb_age |
---|---|---|---|
1 | 1 | pppp | 18 |
2 | 2 | sss | 128 |
子類student表 | hb_id | hb_name | hb_age | hb_school |
---|---|---|---|---|
1 | 2 | sss | 128 | zz |
查詢操作
@Test
public void testGetPerson(){
List person = session.createQuery("from Person ").list();
System.out.println(person);
List student = session.createQuery("from Student ").list();
System.out.println(student);
}
Hibernate:
select
person0_.hb_id as hb1_9_,
person0_.hb_name as hb2_9_,
person0_.hb_age as hb3_9_,
person0_.hb_school as hb1_10_,
person0_.clazz_ as clazz_
from
( select
hb_id,
hb_name,
hb_age,
null as hb_school,
as clazz_
from
mage.hb_person
union
select
hb_id,
hb_name,
hb_age,
hb_school,
as clazz_
from
hb_student
) person0_
[Person{id=, name='pppp', age=}, Person{id=, name='sss', age=}]
Hibernate:
select
student0_.hb_id as hb1_9_,
student0_.hb_name as hb2_9_,
student0_.hb_age as hb3_9_,
student0_.hb_school as hb1_10_
from
hb_student student0_
[Person{id=, name='sss', age=}]
=destroy=
Process finished with exit code
無需使用辨識者列。
子類可以添加非空限制。
多了備援字段。
更新操作
@Test
public void testUpdatePerson(){
String hql = "update Person p set p.age = 120";
session.createQuery(hql).executeUpdate();
}
Hibernate:
create temporary table if not exists HT_hb_person (hb_id integer not null)
Hibernate:
insert into HT_hb_person select person0_.hb_id as hb_id from
( select hb_id, hb_name, hb_age, null as hb_school, as clazz_ from mage.hb_person
union
select hb_id, hb_name, hb_age, hb_school, as clazz_ from hb_student
) person0_
Hibernate:
update mage.hb_person set hb_age=
where ( hb_id ) IN ( select hb_id from HT_hb_person )
Hibernate:
update mage.hb_person set hb_age=
where (hb_id ) IN ( select hb_id from HT_hb_person )
Hibernate:
update hb_student set hb_age=
where (hb_id) IN ( select hb_id from HT_hb_person)
Hibernate:
drop temporary table HT_hb_person
=destroy=
Process finished with exit code
若更新父類屬性,則效率比較低