[原創]java WEB學習筆記87:Hibernate學習之路-- -映射 繼承關系(subclass , joined-subclass,union-subclass )


本博客的目的:①總結自己的學習過程,相當於學習筆記 ②將自己的經驗分享給大家,相互學習,互相交流,不可商用

內容難免出現問題,歡迎指正,交流,探討,可以留言,也可以通過以下方式聯系。

本人互聯網技術愛好者,互聯網技術發燒友

微博:伊直都在0221

QQ:951226918

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

1.繼承映射

  舉例:對於面向對象的程序設計語言而言,繼承和多態是兩個最基本的概念。Hibernate 的繼承映射可以理解持久化類之間的繼承關系。例如:人和學生之間的關系。學生繼承了人,可以認為學生是一個特殊的人,如果對人進行查詢,學生的實例也將被得到。

 

                   

 

 

 

  1)Hibernate支持三種繼承映射策略

    ① 使用 subclass 進行映射:將域模型中的每一個實體對象映射到一個獨立的表中,也就是說不用在關系數據模型中考慮域模型中的繼承關系和多態。

    ② 使用 joined-subclass 進行映射: 對於繼承關系中的子類使用同一個表,這就需要在數據庫表中增加額外的區分子類類型的字段。

    ③ 使用 union-subclass 進行映射:域模型中的每個類映射到一個表,通過關系數據模型中的外鍵來描述表之間的繼承關系。這也就相當於按照域模型的結構來建立數據庫中的表,並通過外鍵來建立表之間的繼承關系。

 

 

 

 

2.采用 subclass 元素的繼承映射

  1)采用 subclass 的繼承映射可以實現對於繼承關系中父類和子類使用同一張表

  2)因為父類和子類的實例全部保存在同一個表中,因此需要在該表內增加一列,使用該列來區分每行記錄到低是哪個類的實例----這個列被稱為辨別者列(discriminator).

  3)在這種映射策略下,使用 subclass 來映射子類,使用 class 或 subclass 的 discriminator-value 屬性指定辨別者列的值

    

 1 <hibernate-mapping package="com.jason.hibernate.entities.subclass">
 2 
 3     <class name="Person" table="PERSONS" discriminator-value="Person">
 4     
 5         <id name="id" type="java.lang.Integer">
 6             <column name="ID" />
 7             <generator class="native" />
 8         </id>
 9         
10         <!-- 配置辨別者列 --> 11 <discriminator column="TYPE" type="string" ></discriminator>
12         
13         
14         <property name="name" type="java.lang.String">
15             <column name="NAME" />
16         </property>
17         
18         <property name="age" type="int">
19             <column name="AGE" />
20         </property>
21         
22        <!-- 映射子類Student,使用subclass 進行映射 --> 23 <subclass name="Student" discriminator-value="Student"> 24 <property name="school" type="string" column="SCHOOL"></property> 25 </subclass> 26  
27     </class>
28 </hibernate-mapping>

 

 

  4)所有子類定義的字段都不能有非空約束。如果為那些字段添加非空約束,那么父類的實例在那些列其實並沒有值,這將引起數據庫完整性沖突,導致父類的實例無法保存到數據庫中

 

  5)代碼

 1  package com.jason.hibernate.entities.subclass;
 2 
 3 public class Person {
 4 
 5     private Integer id;
 6     private String name;
 7     private int age;
 8 
 9     public Integer getId() {
10         return id;
11     }
12 
13     public void setId(Integer id) {
14         this.id = id;
15     }
16 
17     public String getName() {
18         return name;
19     }
20 
21     public void setName(String name) {
22         this.name = name;
23     }
24 
25     public int getAge() {
26         return age;
27     }
28 
29     public void setAge(int age) {
30         this.age = age;
31     }
32 
33 }
Person
 1 package com.jason.hibernate.entities.subclass;
 2 
 3 public class Student extends Person {
 4 
 5     private String school;
 6 
 7     public String getSchool() {
 8         return school;
 9     }
10 
11     public void setSchool(String school) {
12         this.school = school;
13     }
14     
15     
16 }
Student
 1 <?xml version="1.0"?>
 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
 4 
 5 <hibernate-mapping package="com.jason.hibernate.entities.subclass">
 6 
 7     <class name="Person" table="PERSONS" discriminator-value="Person">
 8     
 9         <id name="id" type="java.lang.Integer">
10             <column name="ID" />
11             <generator class="native" />
12         </id>
13         
14         <!-- 配置辨別者列 -->
15         <discriminator column="TYPE" type="string" ></discriminator>
16         
17         
18         <property name="name" type="java.lang.String">
19             <column name="NAME" />
20         </property>
21         
22         <property name="age" type="int">
23             <column name="AGE" />
24         </property>
25         
26         <!-- 映射子類Student,使用subclass 進行映射 -->
27         <subclass name="Student" discriminator-value="Student">
28             <property name="school" type="string" column="SCHOOL"></property>
29         </subclass>
30         
31     </class>
32 </hibernate-mapping>
Person.hbm.xml
  1 package com.jason.hibernate.entities.subclass;
  2 
  3 import java.util.List;
  4 
  5 import org.hibernate.Session;
  6 import org.hibernate.SessionFactory;
  7 import org.hibernate.Transaction;
  8 import org.hibernate.cfg.Configuration;
  9 import org.hibernate.service.ServiceRegistry;
 10 import org.hibernate.service.ServiceRegistryBuilder;
 11 import org.junit.After;
 12 import org.junit.Before;
 13 import org.junit.Test;
 14 
 15 public class HibernateTest {
 16 
 17     private SessionFactory sessionFactory;
 18     private Session session;
 19     private Transaction transaction;
 20     
 21 
 22     // 創建上述三個對象
 23     @Before
 24     public void init() {
 25         Configuration configuration = new Configuration().configure();
 26         ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
 27                 .applySettings(configuration.getProperties())
 28                 .buildServiceRegistry();
 29 
 30         sessionFactory = configuration.buildSessionFactory(serviceRegistry);
 31 
 32         session = sessionFactory.openSession();
 33 
 34         transaction = session.beginTransaction();
 35     }
 36 
 37     // 關閉上述三個對象
 38     @After
 39     public void destroy() {
 40         transaction.commit();
 41         session.close();
 42         sessionFactory.close();
 43     }
 44 
 45     
 46     /**
 47      * subclass 方法缺點
 48      * 1. 使用了辨別者列
 49      * 2. 子類獨有的字段不能添加非空約束
 50      * 3. 若繼承層次較深,數據表的字段較多
 51      * 
 52      */
 53     
 54     
 55     /**
 56      * 
 57      * @Title: testSubClass 
 58      * @Description: 插入操作
 59      *    
 60      * 1.對於子類對象只需要把記錄出入到一張數據表中
 61      * 2.辨別者列由hibernate 自動維護
 62      */
 63     
 64     @Test
 65     public void testSubClass(){
 66         
 67         Person person = new Person();
 68         person.setAge(22);
 69         person.setName("AA");
 70         
 71         session.save(person);
 72         
 73         Student student = new Student();
 74         student.setAge(23);
 75         student.setName("BB");
 76         student.setSchool("xian");
 77         
 78         session.save(student);
 79     }
 80     
 81     
 82     /**
 83      * @Title: testQuery 
 84      * @Description: 查詢
 85      * 1.查詢父類記錄,只需要查詢一張表
 86      * 2.對於子類記錄,只需要查詢一張表
 87      */
 88     @Test
 89     public void testQuery(){
 90         List<Person> persons = session.createQuery("FROM Person").list();
 91         System.out.println(persons.size());
 92         
 93         List<Student> students = session.createQuery("FROM Student").list();
 94         System.out.println(students.size());
 95     }    
 96 
 97     
 98     
 99     
100     
101 }
HibernateTest

 

 

 6)結果

 

 

 

2.采用 joined-subclass 元素的繼承映射

  1)采用 joined-subclass 元素的繼承映射可以實現每個子類一張表

  2)采用這種映射策略時,父類實例保存在父類表中,子類實例由父類表和子類表共同存儲。因為子類實例也是一個特殊的父類實例,因此必然也包含了父類實例的屬性。於是將子類和父類共有的屬性保存在父類表中,子類增加的屬性,則保存在子類表中。

  3)在這種映射策略下,無須使用鑒別者列,但需要為每個子類使用 key 元素映射共有主鍵

  

 1 <?xml version="1.0"?>
 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
 4 
 5 <hibernate-mapping package="com.jason.hibernate.entities.joined.subclass">
 6 
 7     <class name="Person" table="PERSONS" discriminator-value="Person">
 8     
 9         <id name="id" type="java.lang.Integer">
10             <column name="ID" />
11             <generator class="native" />
12         </id>
13         
14         
15         <property name="name" type="java.lang.String">
16             <column name="NAME" />
17         </property>
18         
19         <property name="age" type="int">
20             <column name="AGE" />
21         </property>
22         
23         <!-- 映射子類Student,使用joined-subclass 進行映射 --> 24 <joined-subclass name="Student" table="STUDENTS"> 25 <key column="STUDENT_ID"></key> 26 <property name="school" type="string" column="SCHOOL"></property> 27 </joined-subclass>
28         
29     
30     </class>
31 </hibernate-mapping>

 

  4)子類增加的屬性可以添加非空約束。因為子類的屬性和父類的屬性沒有保存在同一個表中

  5)代碼

Person
Student

 

 1 <?xml version="1.0"?>
 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
 4 
 5 <hibernate-mapping package="com.jason.hibernate.entities.joined.subclass">
 6 
 7     <class name="Person" table="PERSONS" discriminator-value="Person">
 8     
 9         <id name="id" type="java.lang.Integer">
10             <column name="ID" />
11             <generator class="native" />
12         </id>
13         
14         
15         <property name="name" type="java.lang.String">
16             <column name="NAME" />
17         </property>
18         
19         <property name="age" type="int">
20             <column name="AGE" />
21         </property>
22         
23         <!-- 映射子類Student,使用joined-subclass 進行映射 -->
24         <joined-subclass name="Student" table="STUDENTS">
25             <key column="STUDENT_ID"></key>
26             <property name="school" type="string" column="SCHOOL"></property>        
27         </joined-subclass>
28         
29     
30     </class>
31 </hibernate-mapping>
Person.hbm.xml  

 

  1 package com.jason.hibernate.entities.joined.subclass;
  2 
  3 import java.util.List;
  4 
  5 import org.hibernate.Session;
  6 import org.hibernate.SessionFactory;
  7 import org.hibernate.Transaction;
  8 import org.hibernate.cfg.Configuration;
  9 import org.hibernate.service.ServiceRegistry;
 10 import org.hibernate.service.ServiceRegistryBuilder;
 11 import org.junit.After;
 12 import org.junit.Before;
 13 import org.junit.Test;
 14 
 15 public class HibernateTest {
 16 
 17     private SessionFactory sessionFactory;
 18     private Session session;
 19     private Transaction transaction;
 20     
 21 
 22     // 創建上述三個對象
 23     @Before
 24     public void init() {
 25         Configuration configuration = new Configuration().configure();
 26         ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
 27                 .applySettings(configuration.getProperties())
 28                 .buildServiceRegistry();
 29 
 30         sessionFactory = configuration.buildSessionFactory(serviceRegistry);
 31 
 32         session = sessionFactory.openSession();
 33 
 34         transaction = session.beginTransaction();
 35     }
 36 
 37     // 關閉上述三個對象
 38     @After
 39     public void destroy() {
 40         transaction.commit();
 41         session.close();
 42         sessionFactory.close();
 43     }
 44 
 45     
 46     /**
 47      * joined-subclass 方式優點
 48      * 1. 不需要使用辨別者列
 49      * 2. 子類獨有的字段可以添加非空約束
 50      * 3. 沒有冗余的字段
 51      * 
 52      */
 53     
 54     
 55     /**
 56      * 
 57      * @Title: testSubClass 
 58      * @Description: 插入操作
 59      *    
 60      * 1.對於子類記錄需要插入多張表
 61      *
 62      *
 63      */
 64     
 65     @Test
 66     public void testSubClass(){
 67         
 68         Person person = new Person();
 69         person.setAge(22);
 70         person.setName("AA");
 71         
 72         session.save(person);
 73         
 74         Student student = new Student();
 75         student.setAge(23);
 76         student.setName("BB");
 77         student.setSchool("xian");
 78         
 79         session.save(student);
 80     }
 81     
 82     
 83     /**
 84      * @Title: testQuery 
 85      * @Description: 查詢
 86      * 1.查詢父類記錄,只需要查詢一張表
 87      * 2.對於子類記錄,做一個內連接查詢
 88      */
 89     @Test
 90     public void testQuery(){
 91         List<Person> persons = session.createQuery("FROM Person").list();
 92         System.out.println(persons.size());
 93         
 94         List<Student> students = session.createQuery("FROM Student").list();
 95         System.out.println(students.size());
 96     }    
 97 
 98     
 99     
100     
101     
102 }
HibernateTest

 

 

 

 

3.采用 union-subclass 元素的繼承映射

  1)采用 union-subclass 元素可以實現將每一個實體對象映射到一個獨立的表中

1         <union-subclass name="Student" table="STUDENTS">
2             <property name="school" column="SCHOOL" type="string"></property>
3         </union-subclass>
4         

 

  2)子類增加的屬性可以有非空約束 --- 即父類實例的數據保存在父表中,而子類實例的數據保存在子類表中。

  3)子類實例的數據僅保存在子類表中, 而在父類表中沒有任何記錄

  4)在這種映射策略下,子類表的字段會比父類表的映射字段要多,因為子類表的字段等於父類表的字段、加子類增加屬性的總和

  5)在這種映射策略下,既不需要使用鑒別者列,也無須使用 key 元素來映射共有主鍵.

  6)使用 union-subclass 映射策略是不可使用 identity 的主鍵生成策略, 因為同一類繼承層次中所有實體類都需要使用同一個主鍵種子, 即多個持久化實體對應的記錄的主鍵應該是連續的. 受此影響, 也不該使用 native 主鍵生成策略, 因為 native 會根據數據庫來選擇使用 identity 或 sequence.

 

              

 

   

  7)代碼

Person
Student
 1 <?xml version="1.0"?>
 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
 4 
 5 <hibernate-mapping package="com.jason.hibernate.entities.union.subclass">
 6 
 7     <class name="Person" table="PERSONS" >
 8     
 9         <id name="id" type="java.lang.Integer">
10             <column name="ID" />
11             <generator class="hilo" />
12         </id>
13         
14         
15         <property name="name" type="java.lang.String">
16             <column name="NAME" />
17         </property>
18         
19         <property name="age" type="int">
20             <column name="AGE" />
21         </property>
22         
23         
24         
25         <union-subclass name="Student" table="STUDENTS">
26             <property name="school" column="SCHOOL" type="string"></property>
27         </union-subclass>
28         
29     
30     </class>
31 </hibernate-mapping>
Person.hbm.xml
  1 package com.jason.hibernate.entities.union.subclass;
  2 
  3 import java.util.List;
  4 
  5 import org.hibernate.Session;
  6 import org.hibernate.SessionFactory;
  7 import org.hibernate.Transaction;
  8 import org.hibernate.cfg.Configuration;
  9 import org.hibernate.service.ServiceRegistry;
 10 import org.hibernate.service.ServiceRegistryBuilder;
 11 import org.junit.After;
 12 import org.junit.Before;
 13 import org.junit.Test;
 14 
 15 public class HibernateTest {
 16 
 17     private SessionFactory sessionFactory;
 18     private Session session;
 19     private Transaction transaction;
 20     
 21 
 22     // 創建上述三個對象
 23     @Before
 24     public void init() {
 25         Configuration configuration = new Configuration().configure();
 26         ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
 27                 .applySettings(configuration.getProperties())
 28                 .buildServiceRegistry();
 29 
 30         sessionFactory = configuration.buildSessionFactory(serviceRegistry);
 31 
 32         session = sessionFactory.openSession();
 33 
 34         transaction = session.beginTransaction();
 35     }
 36 
 37     // 關閉上述三個對象
 38     @After
 39     public void destroy() {
 40         transaction.commit();
 41         session.close();
 42         sessionFactory.close();
 43     }
 44 
 45     
 46     /**
 47      * union-subclass 方式優點
 48      * 1. 不需要使用辨別者列
 49      * 2. 子類獨有的字段可以添加非空約束
 50      * 
 51      * 缺點:
 52      * 1.存在冗余的字段
 53      * 2.若更新父表的字段,則更新的效率比較低
 54      * 
 55      */
 56     
 57     
 58     /**
 59      * 
 60      * @Title: testSubClass 
 61      * @Description: 插入操作    
 62      * 1.不錯
 63      
 64      */
 65     
 66     @Test
 67     public void testSubClass(){
 68         
 69         Person person = new Person();
 70         person.setAge(22);
 71         person.setName("AA");
 72         
 73         session.save(person);
 74         
 75         Student student = new Student();
 76         student.setAge(23);
 77         student.setName("BB");
 78         student.setSchool("xian");
 79         
 80         session.save(student);
 81     }
 82     
 83     
 84     /**
 85      * @Title: testQuery 
 86      * @Description: 查詢
 87      * 1.查詢父類記錄,需把父表和子表匯總到一起查詢,性能稍差
 88      * 2.對於子類記錄,做一個內連接查詢
 89      */
 90     @Test
 91     public void testQuery(){
 92         List<Person> persons = session.createQuery("FROM Person").list();
 93         System.out.println(persons.size());
 94         
 95         List<Student> students = session.createQuery("FROM Student").list();
 96         System.out.println(students.size());
 97     }    
 98     
 99     
100 }
HibernateTest

 

 

 

 

  4.三種方式的性能比較

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM