首页 > 代码库 > Hibernate5--课程笔记5
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 }
Hibernate5--课程笔记5