Hibernate入門(三)—— 一對多、多對多關系


一、一對多關系

1.概念

​   一對多關系是關系型數據庫中兩個表之間的一種關系。通常在數據庫層級中,兩表之間是有主外鍵關系的。在ORM中,如何通過對象描述表之間的關系,是ORM核心。

2.Hibernate的一對多關聯映射【重點】

2.1表關系的分析

MySql語句

CREATE TABLE `t_category` (
  `cid` int(11) NOT NULL AUTO_INCREMENT,
  `cname` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`cid`)
);
​
CREATE TABLE `t_product` (
  `pid` int(11) NOT NULL AUTO_INCREMENT,
  `pname` varchar(255) DEFAULT NULL,
  `price` double DEFAULT NULL,
  `cid` int(11) DEFAULT NULL,
  PRIMARY KEY (`pid`),
  KEY `FKq8yr5sflwtcj3jqp58x0oy7lx` (`cid`),
  CONSTRAINT `FKq8yr5sflwtcj3jqp58x0oy7lx` FOREIGN KEY (`cid`) REFERENCES `t_category` (`cid`)
);

2.2創建持久化類

  • Category.java(一的一方)

     1 public class Category {
     2     private Integer cid;
     3     private String cname;
     4     //在一的一方,用一個集合表示和product的關系
     5     private Set<Product> products = new HashSet<Product>();
     6     
     7     public Integer getCid() {
     8         return cid;
     9     }
    10     public void setCid(Integer cid) {
    11         this.cid = cid;
    12     }
    13     public String getCname() {
    14         return cname;
    15     }
    16     public void setCname(String cname) {
    17         this.cname = cname;
    18     }
    19     public Set<Product> getProducts() {
    20         return products;
    21     }
    22     public void setProducts(Set<Product> products) {
    23         this.products = products;
    24     }
    25 }
  • Product.java(多的一方)

     1 public class Product {
     2     private Integer pid;
     3     private String pname;
     4     private double price;
     5     //用一個對象表示,當前商品屬於哪個類別
     6     private Category category;
     7  8     public Integer getPid() {
     9         return pid;
    10     }
    11 12     public void setPid(Integer pid) {
    13         this.pid = pid;
    14     }
    15 16     public String getPname() {
    17         return pname;
    18     }
    19 20     public void setPname(String pname) {
    21         this.pname = pname;
    22     }
    23 24     public double getPrice() {
    25         return price;
    26     }
    27 28     public void setPrice(double price) {
    29         this.price = price;
    30     }
    31 32     public Category getCategory() {
    33         return category;
    34     }
    35 36     public void setCategory(Category category) {
    37         this.category = category;
    38     }
    39     
    40 }
2.3創建映射
  • 分類的映射

    <hibernate-mapping>
        <class name="com.pri.bean.Category" table="t_category">
            <!--一,主鍵屬性  -->
            <id name="cid" column="cid">
                <generator class="native"></generator>
            </id>
            <!-- 二,其它屬性 -->
            <property name="cname" column="cname"/>
        
            <!-- 三,表示和商品的關系 -->
            <!--3.1 set標簽的name屬性:多的一方的集合的名字  -->
            <set name="products">
                <!--3.2 key的 column表示多的一方外鍵名 -->
                <key column="cid"/>
                <!--3.3 one-to-many的class屬性表示多的一方類的全限定名  -->
                <one-to-many class="com.pri.bean.Product"/>
            </set>
        </class>
    </hibernate-mapping>
  • 商品的映射

    <hibernate-mapping>
        <class name="com.pri.bean.Product" table="t_product">
            <!--一,主鍵屬性  -->
            <id name="pid" column="pid">
                <generator class="native"></generator>
            </id>
            <!-- 二,其它屬性 -->
            <property name="pname" column="pname"/>
            <property name="price" column="price"/>
        
            <!-- 三,表示和分類的關系 -->
            <!--3.1name:一的一方對象的名字
                  class: 一的一方類的全限定名
                  column:外鍵的名字
              -->
            <many-to-one name="category" class="com.pri.bean.Category" column="cid"/>
        </class>
    </hibernate-mapping>
2.4將映射添加到配置文件
<!-- 三、加載映射關系配置 -->
<mapping resource="com/pri/bean/Product.hbm.xml"/>
<mapping resource="com/pri/bean/Category.hbm.xml"/>

2.5寫代碼測試

  • TestDb

    public class TestDb {
        
        @Test
        public void fun01(){
            Session session = HibernateUtils.openSession();
             Transaction transaction = session.beginTransaction();
           
             transaction.commit();
             session.close();
        }
    ​
    }

3.級聯操作

3.1概念

​   如果我們對某一個表進行了操作,那么也會順帶對關聯表進行操作。或者說當對主對象進行某種操作時是也對其關聯的從對象也作類似的操作.

​   eg:如果我們刪除了一個公司,那么就得要求,員工表也得把屬於這個公司的所有員工也刪除掉。

​   如果我們刪除了一個類別, 那么該類別下的商品是否要刪除或者不刪除只刪除外鍵,那么這樣的操作就屬於級聯操作了.

3.2 級聯保存和修改
3.2.1 操作一方級聯保存多方【掌握】
  • 保存Category(一的一方)的時候級聯保存Product(多的一方)

  • 應用場景: 保存一方的同時也需要保存多方(並且多方的數據比較多). eg: 訂單和訂單項

  • <!-- 三、表示和商品的關系 -->
    <!-- 3.1 set標簽的name屬性:多的一方的集合的名字 -->
    <set name="products" cascade="save-update"/>
        <!-- 3.2 key的column表示多的一方外鍵名 -->
        <key column="cid"/>
        <!-- 3.3 one-to-many的class屬性表示多的一方類的全限定名 -->
        <one-to-many class="com.pri.bean.Product"/>
    </set>
 1    /**
 2     * 只保存分類,通過級聯把當前分類下的商品也保存
 3      * 配置: 在category.hbm.xml下設置:
 4      *      <set cascade="save-update">
 5      */
 6     @Test
 7     public void fun02(){
 8         Session session = HibernateUtils.openSession();
 9         Transaction transaction = session.beginTransaction();
10         
11         Category c1 = new Category();
12         c1.setCname("水果");
13         
14         Product p1 = new Product();
15         p1.setPname("蘋果");
16         p1.setPrice(5);
17         
18         //c1和p1 產生關系
19         c1.getProducts().add(p1);
20         //p1和c1產生關系
21         p1.setCategory(c1);
22         session.save(c1);
23         //session.save(p1);不需要了,通過級聯保存特性自動保存
24         transaction.commit();
25         session.close();
26     }
3.2.2操作多方級聯保存一方【了解】

 

 

 

 

<!--三.表示和分類的關系 -->
<!-- 3.1 name:一的一方對象的名字
        class: 一的一方類的全限定名
        column:外鍵的名字
-->
<many-to-one name="category" class="com.pri.bean.Category" column="cid" cascade="save-update"/>
  • 保存Product(多的一方的)的時候級聯保存Category(一的一方)

     1    /**
     2      * 只保存商品,通過級聯的特性保存商品對應的分類
     3      * 配置: 在product.hbm.xml下設置:
     4      *      <many-to-one cascade="save-update"/>
     5      */
     6     @Test
     7     public void fun03(){
     8         Session session = HibernateUtils.openSession();
     9         Transaction transaction = session.beginTransaction();
    10         
    11         Category c1 = new Category();
    12         c1.setCname("水果");
    13         
    14         Product p1 = new Product();
    15         p1.setPname("蘋果");
    16         p1.setPrice(5);
    17         
    18         //p1和c1發生關系
    19         p1.setCategory(c1);
    20         
    21         session.save(p1);
    22       
    23         //session.save(c1); 不需要了
    24         
    25         transaction.commit();
    26         session.close();
    27     }
3.3級聯刪除
3.3.1刪除一方級聯刪除多方【掌握】
  • 刪除Category(一的一方)的時候級聯刪除Product(多的一方)

  • 場景: 刪除一方的時候確保多方的數據沒有任何用途的時候的才會用. eg: 公司和員工

  • 實際開發里面很少刪除用戶的數據. 通常用一個字段標識的

  • <!--  三.表示和商品的關系 -->
    <!-- 3.1 set標簽的name屬性:多的一方的集合的名字 -->
    <set name="products" cascade="delete">
        <!--3.2 key 的column表示多的一方外鍵名 -->
        <key column="cid"/>
        <!-- 3.3 one-to-many的class屬性表示多的一方類的全限定名 -->
        <one-to-many class="com.pri.bean.Product"/>
    </set>
  •  1 @Test
     2 //級聯刪除商品: 刪除id為1的類別,級聯刪除當前類別下的所有商品
     3 //因為刪除的是類別,所有在Category.hbm.xml配置:<set name="products" cascade="delete">
     4 public void fun03(){
     5       Session session = HibernateUtils.getCurrentSession();
     6       Transaction transaction = session.beginTransaction();
     7                  
     8       //先查 id為1的類別
     9       Category category = session.get(Category.class, 1);
    10       session.delete(category);
    11       transaction.commit();
    12 }
3.3.2 刪除多方級聯刪除一方【了解】
  • 刪除Product(多的一方)的時候級聯刪除Category(一的一方)

    <!--三.表示和分類的關系 -->
         <!-- 3.1 name:一的一方對象的名字
                 class: 一的一方類的全限定名
                 column:外鍵的名字
         -->
    <many-to-one name="category" class="com.pri.bean.Category" column="cid" cascade="delete"/>
 1    @Test
 2      //級聯刪除分類: 刪除id為1的商品,級聯刪除這個商品所屬的類別(了解)
 3      //把當前id為1商品刪除,把這個商品所屬的類別刪除, 商品表里面該類別其它的商品的記錄的外鍵置為null;
 4      public void fun04(){
 5          Session session = HibernateUtils.getCurrentSession();
 6          Transaction transaction = session.beginTransaction();
 7          
 8          //先查 id為1的類別
 9          Product product = session.get(Product.class, 1);
10          session.delete(product);
11          
12          
13          transaction.commit();
14      }

4.外鍵維護

4.1 雙向關聯產生多余的SQL語句

​   一旦存在主外鍵關系,那么外鍵就由雙方對象去維護了, 那么就會造成對這個外鍵執行了多次操作, 有一次操作其實可以避免的。 也就是說這個外鍵只要讓一個人去維護即可。 外鍵屬於誰,就讓誰去維護。

  • eg:修改產品對應的類別

4.2inverse標簽屬性
4.2.1概念

  inverse:外鍵維護,默認為false。代表一方不去維護多方外鍵。(inverse有反轉的意思)

  外鍵屬於誰, 誰就負責維護.

4.2.2一方的放棄外鍵維護
  • 只能在一的一方放棄外鍵維護

    <set  inverse="true">
        ...
    </set>
  • EG:

  • <!--  三.表示和商品的關系 -->
    <!-- 3.1 set標簽的name屬性:多的一方的集合的名字 -->
    <set name="products" cascade="delete" inverse="true">
        <!--3.2 key 的column表示多的一方外鍵名 -->
        <key column="cid"/>
        <!-- 3.3 one-to-many的class屬性表示多的一方類的全限定名 -->
        <one-to-many class="com.pri.bean.Product"/>
    </set>
 1 /**
 2    * 把蘋果(p1)的類別設置為水果(c2)
 3      * 衣服是(c1)
 4      */
 5     @Test
 6     public void fun02(){
 7         Session session = HibernateUtils.openSession();
 8         Transaction transaction = session.beginTransaction();
 9         //獲得蘋果
10         Product p1 = session.get(Product.class, 1);
11         //獲得食物類別
12         Category c2 = session.get(Category.class, 2);
13         
14         //p1和c2關聯
15         p1.setCategory(c2);
16         //c2和p1關聯
17         c2.getProducts().add(p1);
18         
19         transaction.commit();
20         session.close();
21     }

二、多對多的關系

1.概念

​ 多對多關系是關系數據庫中兩個表之間的一種數據關系,為了維護這種關系,通常會存在一張中間關系表。兩張表都只和關系表間建立主外鍵關系。

2.Hibernate的多對多關聯映射【重點】

2.1表關系的分析

  • MySql語句

2.2創建實體
  • Student.java

     1 public class Student {
     2     
     3     private Integer sid;
     4     private String sname;
     5     
     6     private Set<Course> courses = new HashSet<Course>();
     7  8     public Integer getSid() {
     9         return sid;
    10     }
    11 12     public void setSid(Integer sid) {
    13         this.sid = sid;
    14     }
    15 16     public String getSname() {
    17         return sname;
    18     }
    19 20     public void setSname(String sname) {
    21         this.sname = sname;
    22     }
    23 24     public Set<Course> getCourses() {
    25         return courses;
    26     }
    27 28     public void setCourses(Set<Course> courses) {
    29         this.courses = courses;
    30     }
    31     
    32 33     
    34 }
  • Course.java

     1 public class Course {
     2     
     3     private Integer cid;
     4     private String cname;
     5     
     6     private Set<Student> students = new HashSet<Student>();
     7  8     public Integer getCid() {
     9         return cid;
    10     }
    11 12     public void setCid(Integer cid) {
    13         this.cid = cid;
    14     }
    15 16     public String getCname() {
    17         return cname;
    18     }
    19 20     public void setCname(String cname) {
    21         this.cname = cname;
    22     }
    23 24     public Set<Student> getStudents() {
    25         return students;
    26     }
    27 28     public void setStudents(Set<Student> students) {
    29         this.students = students;
    30     }
    31      
    32 }
2.3創建映射
  • 學生的映射

     1 <hibernate-mapping>
     2     <class name="com.itheima.bean.Student" table="t_student">
     3         <!--一,主鍵屬性  -->
     4         <id name="sid" column="sid">
     5             <generator class="native"></generator>
     6         </id>
     7         <!-- 二,其它屬性 -->
     8         <property name="sname" column="sname"/>
     9     
    10         <!-- 三,表示和課程的關系 -->
    11         <!--3.1 set標簽的name屬性:當前類中集合的名字 
    12                 table:第三方表名
    13              -->
    14         <set name="courses" table="s_c_tab">
    15             <!--3.2 key的 column表示當前類在中間表中的外鍵 -->
    16             <key column="sid" />
    17                 <!--3.3 many-to-many表示多對多關系
    18                     column:表示另一方在中間表中的外鍵
    19                     class:表示另一方類的全限定名
    20               -->
    21             <many-to-many column="cid" class="com.itheima.bean.Course" ></many-to-many>
    22         </set>
    23     </class>
    24 </hibernate-mapping>
  • 課程的映射

     1 <hibernate-mapping>
     2     <class name="com.itheima.bean.Course" table="t_course">
     3         <!--一,主鍵屬性  -->
     4         <id name="cid" column="cid">
     5             <generator class="native"></generator>
     6         </id>
     7         <!-- 二,其它屬性 -->
     8         <property name="cname" column="cname"/>
     9     
    10         <!-- 三,表示和課程的關系 -->
    11         <!--3.1 set標簽的name屬性:當前類中集合的名字  
    12             table:第三方表名
    13         -->
    14         <set name="students" table="s_c_tab">
    15             <!--3.2 key的 column表示當前類在中間表中的外鍵 -->
    16             <key column="cid"/>
    17                 <!--3.3 many-to-many表示多對多關系
    18                     column:表示另一方在中間表中的外鍵
    19                     class:表示另一方類的全限定名
    20               -->
    21             <many-to-many column="sid" class="com.itheima.bean.Student"></many-to-many>
    22         </set>
    23     </class>
    24 </hibernate-mapping>
2.4將映射添加到配置文件
<!-- 三.加載映射關系配置 -->
<mapping resource="com/pri/bean/Student.hbm.xml"/>
<mapping resource="com/pri/bean/Course.hbm.xml"/>

2.5寫代碼測試
  • 保存

     1     /**
     2      * 正常保存
     3      */
     4     @Test
     5     public void fun01(){
     6         Session session = HibernateUtils.openSession();
     7         Transaction transaction = session.beginTransaction();
     8         
     9         Student s1 = new Student();
    10         s1.setSname("張三");
    11         Student s2 = new Student();
    12         s2.setSname("李四");
    13         
    14         Course c1 = new Course();
    15         c1.setCname("C語言");
    16         Course c2 = new Course();
    17         c2.setCname("Java");
    18         Course c3 = new Course();
    19         c3.setCname("前端");
    20         
    21         //s1選擇了c1和c2
    22         s1.getCourses().add(c1);
    23         s1.getCourses().add(c2);
    24         
    25         //s2選擇了c2 c3
    26         s2.getCourses().add(c2);
    27         s2.getCourses().add(c3);
    28         
    29         //c1被s1選了
    30         c1.getStudents().add(s1);
    31         //c2被s1,s2選了
    32         c2.getStudents().add(s1);
    33         c2.getStudents().add(s2);
    34         //c3被s2選了
    35         c3.getStudents().add(s2);
    36         //如果雙向關聯,一定要一方放棄主鍵維護
    37         session.save(s1);
    38         session.save(s2);
    39         session.save(c1);
    40         session.save(c2);
    41         session.save(c3);
    42         
    43         transaction.commit();
    44         session.close();
    45     }

3.級聯操作

3.1級聯保存【掌握】
  • 保存Student級聯保存Course

  • <set name="courses" table="s_c_table" cascade="save-update,delete">
         <!-- 3.2 key的column表示當前類在中間表的外鍵 -->
         <key column="sid"/>
         <!-- 3.3 many-to-many 表示多對對關系
                 column:表示另一方在中間表中的外鍵
                 class:表示另一方類的全限定名
          -->
         <many-to-many class="com.pri.bean.Course" column="cid"/>
    </set>
 1    /**
 2      * 保存Student級聯保存Course
 3      * 在student.hbm.xml里面配置:<set name="courses" table="s_c_tab" cascade="save-update">
 4      */
 5     @Test
 6     public void fun02(){
 7         Session session = HibernateUtils.openSession();
 8         Transaction transaction = session.beginTransaction();
 9         
10         Student s1 = new Student();
11         s1.setSname("張三");
12         Student s2 = new Student();
13         s2.setSname("李四");
14         
15         Course c1 = new Course();
16         c1.setCname("C語言");
17         Course c2 = new Course();
18         c2.setCname("Java");
19         Course c3 = new Course();
20         c3.setCname("前端");
21         
22         //s1選擇了c1和c2
23         s1.getCourses().add(c1);
24         s1.getCourses().add(c2);
25         
26         //s2選擇了c2 c3
27         s2.getCourses().add(c2);
28         s2.getCourses().add(c3);
29         
30         //c1被s1選了
31         c1.getStudents().add(s1);
32         //c2被s1,s2選了
33         c2.getStudents().add(s1);
34         c2.getStudents().add(s2);
35         //c3被s2選了
36         c3.getStudents().add(s2);
37         //如果雙向關聯,一定要一方放棄外鍵維護
38         session.save(s1);
39         session.save(s2);
40     /*  session.save(c1);
41         session.save(c2);
42         session.save(c3);*/
43         
44         transaction.commit();
45         session.close();
46     }
  • 保存Course級聯保存Student

  • <!-- 三.表示和課程的關系 -->
    <!-- 3.1 set標簽的name屬性: 當前類中集合的名字 -->
    <set name="students" table="s_c_table" cascade="save-update" inverse="true">
          <!-- 3.2 key的column表示當前類在中間表的外鍵 -->
          <key column="cid"/>
          <!-- 3.3 many-to-many 表示多對對關系
                  column:表示另一方在中間表中的外鍵
                  class:表示另一方類的全限定名
          -->
          <many-to-many class="com.pri.bean.Student" column="sid"/>
    </set>
 1    /**
 2      * 保存Course級聯保存Student
 3      * 在Course.hbm.xml里面配置:<set  cascade="save-update">
 4      */
 5     @Test
 6     public void fun03(){
 7         Session session = HibernateUtils.openSession();
 8         Transaction transaction = session.beginTransaction();
 9         
10         Student s1 = new Student();
11         s1.setSname("張三");
12         Student s2 = new Student();
13         s2.setSname("李四");
14         
15         Course c1 = new Course();
16         c1.setCname("C語言");
17         Course c2 = new Course();
18         c2.setCname("Java");
19         Course c3 = new Course();
20         c3.setCname("前端");
21         
22         //s1選擇了c1和c2
23         s1.getCourses().add(c1);
24         s1.getCourses().add(c2);
25         
26         //s2選擇了c2 c3
27         s2.getCourses().add(c2);
28         s2.getCourses().add(c3);
29         
30         //c1被s1選了
31         c1.getStudents().add(s1);
32         //c2被s1,s2選了
33         c2.getStudents().add(s1);
34         c2.getStudents().add(s2);
35         //c3被s2選了
36         c3.getStudents().add(s2);
37         //如果雙向關聯,一定要一方放棄主鍵維護
38         /*session.save(s1);
39         session.save(s2);*/
40         session.save(c1);
41         session.save(c2);
42         session.save(c3);
43         
44         transaction.commit();
45         session.close();
46     }
注意的地方:

​ 如果雙向關聯,一定要一方放棄主鍵維護

3.2級聯刪除【了解】
  • 刪除Student,級聯刪除Course 高數

     1   /**
     2     * 配置了級聯刪除 在Student.hbm.xml配置<set name="courses" table="s_c_tab"  cascade="delete">
     3      * 把id為1的學生刪除,
     4      * id為1的學生之前選過: id位1,2的課程.
     5      * 級聯刪除既會刪除正向多方數據庫表中的記錄,也會刪除反向多方表中的記錄和中間關系表中的記錄
     6      */
     7     @Test
     8     public void fun02(){
     9         Session session = HibernateUtils.openSession();
    10         Transaction transaction = session.beginTransaction();
    11         
    12         Student student = session.get(Student.class, 1);
    13         session.delete(student);
    14         
    15         transaction.commit();
    16         session.close();
    17     }

注意的地方:

​ 非級聯刪除只會刪除正向多方數據庫表和中間關系表中的記錄,不會刪除反向多方表中的記錄

​ 級聯刪除既會刪除正向多方數據庫表中的記錄,也會刪除反向多方表中的記錄和中間關系表中的記錄

​ 開發過程中用的比較少

3.3其它操作
  • 某個學生退課

     1  /**
     2     * 某個學生退課
     3      * id為1的學生之前選過: id為1,2的課程.
     4      * 現在的操作是:id為1的學生退掉ID為2的課程
     5      */
     6     @Test
     7     public void fun01(){
     8         Session session = HibernateUtils.openSession();
     9         Transaction transaction = session.beginTransaction();
    10         //獲得id為1的學生
    11         Student s1 = session.get(Student.class, 1);
    12 13         //獲得id為2的課程
    14         Course c2 = session.get(Course.class, 2);
    15         
    16         s1.getCourses().remove(c2);
    17         transaction.commit();
    18         session.close();
    19     }
  • 某個學生改課

     1  /**
     2     * 某個學生退課
     3      * id為1的學生之前選過: id為1,2的課程.
     4      * 現在的操作是:id為1的學生把id為2的課程改成id為3的課程
     5      */
     6     @Test
     7     public void fun02(){
     8         Session session = HibernateUtils.openSession();
     9         Transaction transaction = session.beginTransaction();
    10         //獲得id為1的學生
    11         Student s1 = session.get(Student.class, 1);
    12         //獲得id為2的課程
    13         Course c2 = session.get(Course.class, 2);
    14         Course c3 = session.get(Course.class, 3);
    15         
    16         s1.getCourses().remove(c2);
    17         s1.getCourses().add(c3);
    18         transaction.commit();
    19         session.close();
    20     }


免責聲明!

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



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