Hibernate5笔记5--关联关系映射

关联关系映射:

  关联关系,是使用最多的一种关系,非常重要。在内存中反映为实体关系,映射到DB中为主外键关系实体间的关联,即对外键的维护。关联关系的发生,即对外键数据的改变。

  外键:外面的主键,即,使用其它表的主键值作为自已的某字段的取值。

  (1) 基本概念:

    关联属性:Java代码的实体类定义中,声明的另一个实例类类型或其集合类型的属性,称为关联属性。

    关联关系维护:关联关系的维护,也称为外键维护,即为外键字段赋值。Hibernate默认情况下,关联的双方都具有维护权。即在代码中均可通过调用自己关联属性的set方法来建立关联关系反映到数据库中,即是为外键字段赋值

           不过,由于外键是建立在多方表中的,所以对于外键的维护方式,即为外键字段赋值的方式,一方维护与多方维护,其底层执行是不同的
           若关联关系由一方维护,只能通过update语句来完成。若关联关系由多方维护,通过insert语句来完成。
           虽然双方均具有维护权,但一方同时具有放弃维护权的能力。通过对一方关联属性inverse=“true”设置,即可放弃关联关系维护权,将维护权完全交给多方。

    预处理语句:所谓预处理语句,即当前先不执行,等后面条件成熟,或程序运行完毕再执行的语句。

          当一方具有关联关系的维护权,并且执行save(一方对象)时会产生一条update预处理语句,用于维护外键值。当多方具有关联关系的维护权,并且执行save(多方对象)时,会产生一条insert预处理语句,用于维护外键值。

    级联关系:当对某一类的对象a进行操作,如增加、删除、修改时,同时会自动对另一类的某对象b进行相同的操作。此时称,对象a、b具有级联关系,对象b为对象a的级联对象。

         级联操作是通过映射文件的cascade属性设置的。该属性的值较多,其介绍如下:

          none:在保存、更新或删除当前对象时,忽略其他关联的对象,即不使用级联。它是默认值。
          save-update:当通过Session的save()、update()、saveOrUpdate()方法来保存或更新当前对象时,将级联到其他DB中的相关联的表。
            delete:当通过Session的delete()方法删除当前对象时,将级联删除所有关联的对象。

          all:包含save-update及delete级联的所有行为。另外,当对当前对象执行lock()操作时,也会对所有关联的持久化对象执行lock()操作。
          delete-orphan:删除所有和当前对象解除关联关系的对象。

          all-delete-orphan:包含all和delete-orphan级联的所有行为。

    关联方向:(1)单向关联:指具有关联关系的实体对象间的加载与访问关系是单向的。即,只有一个实体对象可以加载和访问对方,但对方是看不到另一方的。
         (2)双向关联 :指具有关联关系的实体对象间的加载与访问关系是双向的。即,任何一方均可加载和访问另一方。

    关联数量:实体对象间的关系,从数量上可以划分为:1:1,1:n,n:1,m:n

    总结底层执行一对多关系中,一方维护关联关系,先插入多方数据,后插入一方数据,最后update多方表中的外键值(???是否正确);多方维护关联关系,先插入一方数据,后插入多方数据,在插入多方数据的同时插入外键值;

           多对多关系中,哪一方维护关联关系,就是哪一方数据先插入,再插入关联方数据,最后插入中间表数据。

  (2) 1:n单向关联(由一方维护关联关系):

    一方实体类代码:

 1 package com.tongji.beans;
 2 
 3 import java.util.HashSet;
 4 import java.util.Set;
 5 
 6 public class Country {
 7     private Integer cid;
 8     private String cname;
 9     private Set<Minister> ministers;  //关联属性
10     
11     public Country() {
12         super();
13         ministers = new HashSet<Minister>();
14     }
15 
16     public Country(String cname) {
17         this();
18         this.cname = cname;
19     }
20 
21     public Integer getCid() {
22         return cid;
23     }
24 
25     public void setCid(Integer cid) {
26         this.cid = cid;
27     }
28 
29     public String getCname() {
30         return cname;
31     }
32 
33     public void setCname(String cname) {
34         this.cname = cname;
35     }
36 
37     public Set<Minister> getMinisters() {
38         return ministers;
39     }
40 
41     public void setMinisters(Set<Minister> ministers) {
42         this.ministers = ministers;
43     }
44 
45     @Override
46     public String toString() {
47         return "Country [cid=" + cid + ", cname=" + cname + ", ministers=" + ministers + "]";
48     }
49     
50 }

    一方映射文件代码:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE hibernate-mapping PUBLIC 
 3     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 4     "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
 5   
 6 <hibernate-mapping package="com.tongji.beans">
 7     <class name="Country">
 8         <id name="cid">
 9             <generator class="native"/>
10         </id>
11         <property name="cname"/>
12         <!-- 对关联属性的映射,inverse=true,表示一方放弃关联关系的维护权,这个不应该这么设置,只是为了演示错误 -->
13         <set name="ministers" cascade="save-update" inverse="true">
14             <key column="countryId"/>
15             <one-to-many class="Minister"/>
16         </set>
17     </class>
18 </hibernate-mapping>

     其中,column是外键的名称

     测试代码:

 1 @Test
 2 public void test03() {
 3     //1. 获取Session
 4     Session session = HbnUtils.getSession();
 5     try {
 6         //2. 开启事务
 7         session.beginTransaction();
 8         //3. 操作
 9         Minister minsiter1 = new Minister("aaa");
10         Minister minsiter2 = new Minister("bbb");
11         Minister minsiter3 = new Minister("ccc");
12         
13         Country country = new Country("USA");
14         //关联的建立在这里完成
15         country.getMinisters().add(minsiter1);
16         country.getMinisters().add(minsiter2);
17         country.getMinisters().add(minsiter3);
18         
19         session.save(country);
20         //4. 事务提交
21         session.getTransaction().commit();
22     } catch (Exception e) {
23         e.printStackTrace();
24         //5. 事务回滚
25         session.getTransaction().rollback();
26     }
27 }

  (2) 1:n双向关联:

    一方实体类代码和一方映射文件代码同上;

    多方实体类代码:

 1 package com.tongji.beans;
 2 
 3 public class Minister {
 4     private Integer mid;
 5     private String mname;
 6     private Country country;  //关联属性
 7     
 8     public Minister() {
 9         super();
10     }
11 
12     public Minister(String mname) {
13         super();
14         this.mname = mname;
15     }
16 
17     public Integer getMid() {
18         return mid;
19     }
20 
21     public void setMid(Integer mid) {
22         this.mid = mid;
23     }
24 
25     public String getMname() {
26         return mname;
27     }
28 
29     public void setMname(String mname) {
30         this.mname = mname;
31     }
32     
33     public Country getCountry() {
34         return country;
35     }
36 
37     public void setCountry(Country country) {
38         this.country = country;
39     }
40 
41     @Override
42     public String toString() {
43         return "Minister [mid=" + mid + ", mname=" + mname + "]";
44     }
45     
46 }

    多方映射文件代码:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE hibernate-mapping PUBLIC 
 3     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 4     "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
 5   
 6 <hibernate-mapping package="com.tongji.beans">
 7     <class name="Minister">
 8         <id name="mid">
 9             <generator class="native"/>
10         </id>
11         <property name="mname"/>
12         <!-- 关联属性名 -->
13         <many-to-one name="country" cascade="save-update" 
14             class="Country" column="countryId"/>
15     </class>
16 </hibernate-mapping>

    测试代码:

 1 package com.tongji.test;
 2 
 3 import org.hibernate.Session;
 4 import org.junit.Test;
 5 
 6 import com.tongji.beans.Country;
 7 import com.tongji.beans.Minister;
 8 import com.tongji.utils.HbnUtils;
 9 
10 public class MyTest {
11     @Test
12     public void test00() {
13         //1. 获取Session
14         Session session = HbnUtils.getSession();
15         try {
16             //2. 开启事务
17             session.beginTransaction();
18             //3. 操作
19             Minister minister = new Minister("aaa");
20             
21             Country country = new Country("USA");
22             //Country方在维护关联关系
23             country.getMinisters().add(minister);
24             
25             session.save(country);
26             //4. 事务提交
27             session.getTransaction().commit();
28         } catch (Exception e) {
29             e.printStackTrace();
30             //5. 事务回滚
31             session.getTransaction().rollback();
32         }
33     }
34     
35     @Test
36     public void test01() {
37         //1. 获取Session
38         Session session = HbnUtils.getSession();
39         try {
40             //2. 开启事务
41             session.beginTransaction();
42             //3. 操作
43             Minister minister = new Minister("aaa");
44             
45             Country country = new Country("USA");
46             //Minister方在维护关联关系
47             minister.setCountry(country);
48             
49             //谁在维护关联关系,就save()谁
50             session.save(minister);
51             //4. 事务提交
52             session.getTransaction().commit();
53         } catch (Exception e) {
54             e.printStackTrace();
55             //5. 事务回滚
56             session.getTransaction().rollback();
57         }
58     }
59 }

  (3) 自关联:

    实体类代码:

 1 package com.tongji.beans;
 2 
 3 import java.util.HashSet;
 4 import java.util.Set;
 5 
 6 //新闻栏目
 7 public class NewsLabel {
 8     private Integer id;
 9     private String name;  //栏目名称
10     private String content;  //栏目内容
11     private NewsLabel parentNewsLabel;  //父栏目
12     private Set<NewsLabel> childNewsLabels;  //子栏目
13     
14     public NewsLabel() {
15         childNewsLabels = new HashSet<NewsLabel>();
16     }
17 
18     public NewsLabel(String name, String content) {
19         this();
20         this.name = name;
21         this.content = content;
22     }
23 
24     public Integer getId() {
25         return id;
26     }
27 
28     public void setId(Integer id) {
29         this.id = id;
30     }
31 
32     public String getName() {
33         return name;
34     }
35 
36     public void setName(String name) {
37         this.name = name;
38     }
39 
40     public String getContent() {
41         return content;
42     }
43 
44     public void setContent(String content) {
45         this.content = content;
46     }
47 
48     public NewsLabel getParentNewsLabel() {
49         return parentNewsLabel;
50     }
51 
52     public void setParentNewsLabel(NewsLabel parentNewsLabel) {
53         this.parentNewsLabel = parentNewsLabel;
54     }
55 
56     public Set<NewsLabel> getChildNewsLabels() {
57         return childNewsLabels;
58     }
59 
60     public void setChildNewsLabels(Set<NewsLabel> childNewsLabels) {
61         this.childNewsLabels = childNewsLabels;
62     }
63 
64     @Override
65     public String toString() {
66         return "NewsLabel [id=" + id + ", name=" + name + ", content=" + content + "]";
67     }
68     
69 }

    映射文件代码:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE hibernate-mapping PUBLIC 
 3     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 4     "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
 5   
 6 <hibernate-mapping package="com.tongji.beans">
 7     <class name="NewsLabel">
 8         <id name="id">
 9             <generator class="native"/>
10         </id>
11         <property name="name"/>
12         <property name="content"/>
13         <!-- 站在一方角度 -->
14         <set name="childNewsLabels" cascade="save-update">
15             <key column="pid"/>
16             <one-to-many class="NewsLabel"/>
17         </set>
18         <!-- 站在多方角度 -->
19         <many-to-one name="parentNewsLabel" cascade="save-update" 
20             class="NewsLabel" column="pid"/>
21     </class>
22 </hibernate-mapping>

    测试代码:

 1 package com.tongji.test;
 2 
 3 import org.hibernate.Session;
 4 import org.junit.Test;
 5 
 6 import com.tongji.beans.NewsLabel;
 7 import com.tongji.utils.HbnUtils;
 8 
 9 public class MyTest {
10     //让父方栏目维护关联关系,即一方维护
11     @Test
12     public void test00() {
13         //1. 获取Session
14         Session session = HbnUtils.getSession();
15         try {
16             //2. 开启事务
17             session.beginTransaction();
18             //3. 操作
19             NewsLabel footballNews = new NewsLabel("足球新闻","国足国足国足国足");
20             NewsLabel basketballNews = new NewsLabel("篮球新闻","登哥登哥登哥登哥");
21             
22             NewsLabel sportsNews = new NewsLabel("体育新闻","奥运奥运奥运奥运");
23             
24             sportsNews.getChildNewsLabels().add(footballNews);
25             sportsNews.getChildNewsLabels().add(basketballNews);
26             
27             session.save(sportsNews);
28             
29             //4. 事务提交
30             session.getTransaction().commit();
31         } catch (Exception e) {
32             e.printStackTrace();
33             //5. 事务回滚
34             session.getTransaction().rollback();
35         }
36     }
37     
38     //让子方栏目维护关联关系,即多方维护
39     @Test
40     public void test01() {
41         //1. 获取Session
42         Session session = HbnUtils.getSession();
43         try {
44             //2. 开启事务
45             session.beginTransaction();
46             //3. 操作
47             NewsLabel basketballNews = new NewsLabel("篮球新闻","登哥登哥登哥登哥");
48             
49             NewsLabel sportsNews = new NewsLabel("体育新闻","奥运奥运奥运奥运");
50             
51             basketballNews.setParentNewsLabel(sportsNews);
52             
53             session.save(basketballNews);
54             
55             //4. 事务提交
56             session.getTransaction().commit();
57         } catch (Exception e) {
58             e.printStackTrace();
59             //5. 事务回滚
60             session.getTransaction().rollback();
61         }
62     }
63 }

  (4) n:1单向关联(由多方来维护关联关系):

    一方实体类代码和一方映射文件代码为原来不考虑关联时候的样子,多方实体类代码和多方映射文件代码同(3)1:n双向关联,测试代码同(3)1:n双向关联的多方维护部分。

  (5)n:m单向关联:

    维护关联关系的一方的实体类代码:

 1 package com.tongji.beans;
 2 
 3 import java.util.HashSet;
 4 import java.util.Set;
 5 
 6 public class Student {
 7     private Integer sid;
 8     private String sname;
 9     private Set<Course> courses;
10     
11     public Student() {
12         courses = new HashSet<Course>();
13     }
14 
15     public Student(String sname) {
16         this();
17         this.sname = sname;
18     }
19 
20     public Integer getSid() {
21         return sid;
22     }
23 
24     public void setSid(Integer sid) {
25         this.sid = sid;
26     }
27 
28     public String getSname() {
29         return sname;
30     }
31 
32     public void setSname(String sname) {
33         this.sname = sname;
34     }
35 
36     public Set<Course> getCourses() {
37         return courses;
38     }
39 
40     public void setCourses(Set<Course> courses) {
41         this.courses = courses;
42     }
43 
44     @Override
45     public String toString() {
46         return "Student [sid=" + sid + ", sname=" + sname + "]";
47     }
48     
49 }

    维护关联关系的一方的映射文件代码:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE hibernate-mapping PUBLIC 
 3     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 4     "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
 5   
 6 <hibernate-mapping package="com.tongji.beans">
 7     <class name="Student">
 8         <id name="sid">
 9             <generator class="native"/>
10         </id>
11         <property name="sname"/>
12         <!-- 关联属性的映射 -->
13         <set name="courses" cascade="save-update" table="middle">  <!-- table指定多对多关系的中间表  -->
14             <key column="studentId"/>  <!-- 指定当前类在中间表中对应的外键 -->
15             <many-to-many class="Course" column="courseId"/>  <!-- 指定关联类在中间表中对应的外键 -->
16         </set>
17     </class>
18 </hibernate-mapping>

    测试代码:

 1 package com.tongji.test;
 2 
 3 import org.hibernate.Session;
 4 import org.junit.Test;
 5 
 6 import com.tongji.beans.Course;
 7 import com.tongji.beans.Student;
 8 import com.tongji.utils.HbnUtils;
 9 
10 public class MyTest {
11     //第一种解决方案
12     @Test
13     public void test00() {
14         //1. 获取Session
15         Session session = HbnUtils.getSession();
16         try {
17             //2. 开启事务
18             session.beginTransaction();
19             //3. 操作
20             Course course1 = new Course("Struts2");
21             Course course2 = new Course("Hibernate5");
22             Course course3 = new Course("Sring4");
23         
24             Student student1 = new Student("张三");
25             Student student2 = new Student("李四");
26             
27             student1.getCourses().add(course1);
28             student1.getCourses().add(course2);
29             
30             student2.getCourses().add(course1);
31             student2.getCourses().add(course3);
32             
33             session.save(student1);
34             session.save(student2);
35             //4. 事务提交
36             session.getTransaction().commit();
37         } catch (Exception e) {
38             e.printStackTrace();
39             //5. 事务回滚
40             session.getTransaction().rollback();
41         }
42     }
43     
44 }

   (6)n:m双向关联:

      上述另一方实体类代码:

 1 package com.tongji.beans;
 2 
 3 import java.util.HashSet;
 4 import java.util.Set;
 5 
 6 public class Course {
 7     private Integer cid;
 8     private String cname;
 9     private Set<Student> students;
10     
11     public Course() {
12         students = new HashSet<Student>();
13     }
14 
15     public Course(String cname) {
16         this();
17         this.cname = cname;
18     }
19 
20     public Integer getCid() {
21         return cid;
22     }
23 
24     public void setCid(Integer cid) {
25         this.cid = cid;
26     }
27 
28     public String getCname() {
29         return cname;
30     }
31 
32     public void setCname(String cname) {
33         this.cname = cname;
34     }
35     
36     public Set<Student> getStudents() {
37         return students;
38     }
39 
40     public void setStudents(Set<Student> students) {
41         this.students = students;
42     }
43 
44     @Override
45     public String toString() {
46         return "Course [cid=" + cid + ", cname=" + cname + "]";
47     }
48     
49 }

    上述另一方映射文件代码:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE hibernate-mapping PUBLIC 
 3     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 4     "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
 5   
 6 <hibernate-mapping package="com.tongji.beans">
 7     <class name="Course">
 8         <id name="cid">
 9             <generator class="native"/>
10         </id>
11         <property name="cname"/>
12         <!-- 关联属性映射-->
13         <set name="students" cascade="save-update" table="middle">
14             <key column="courseId"/>
15             <many-to-many class="Student" column="studentId"/>
16         </set>
17     </class>
18 </hibernate-mapping>

    测试代码:

 1 package com.tongji.test;
 2 
 3 import org.hibernate.Session;
 4 import org.junit.Test;
 5 
 6 import com.tongji.beans.Course;
 7 import com.tongji.beans.Student;
 8 import com.tongji.utils.HbnUtils;
 9 
10 public class MyTest {
11     @Test
12     public void test00() {
13         //1. 获取Session
14         Session session = HbnUtils.getSession();
15         try {
16             //2. 开启事务
17             session.beginTransaction();
18             //3. 操作
19             Course course1 = new Course("Struts2");
20             Course course2 = new Course("Hibernate5");
21             Course course3 = new Course("Sring4");
22         
23             Student student1 = new Student("张三");
24             Student student2 = new Student("李四");
25             
26             student1.getCourses().add(course1);
27             student1.getCourses().add(course2);
28             
29             student2.getCourses().add(course1);
30             student2.getCourses().add(course3);
31             
32             session.save(student1);
33             session.save(student2);
34             //4. 事务提交
35             session.getTransaction().commit();
36         } catch (Exception e) {
37             e.printStackTrace();
38             //5. 事务回滚
39             session.getTransaction().rollback();
40         }
41     }
42     
43     @Test
44     public void test01() {
45         //1. 获取Session
46         Session session = HbnUtils.getSession();
47         try {
48             //2. 开启事务
49             session.beginTransaction();
50             //3. 操作
51             Course course1 = new Course("Struts2");
52             Course course2 = new Course("Hibernate5");
53             Course course3 = new Course("Sring4");
54         
55             Student student1 = new Student("张三");
56             Student student2 = new Student("李四");
57             
58             course1.getStudents().add(student1);
59             course1.getStudents().add(student2);
60             
61             course2.getStudents().add(student2);
62             
63             course3.getStudents().add(student1);
64             
65             session.save(course1);
66             session.save(course2);
67             session.save(course3);
68             //4. 事务提交
69             session.getTransaction().commit();
70         } catch (Exception e) {
71             e.printStackTrace();
72             //5. 事务回滚
73             session.getTransaction().rollback();
74         }
75     }
76     
77 }
posted @ 2017-01-15 20:51  拉夫德尔  阅读(769)  评论(0编辑  收藏  举报