hibernate的多對多關聯映射


 

  

  在我們實際項目中,多對多的情況也時長存在,比如最常見的就是系統管理的五張表,如下面的一個結構:

 

在本文學習hibernate多對多關聯映射的實驗中我簡單的寫幾個字段,達到學習目的即可。

1.多對多的關系表達

1.關系型數據庫(RDB)中的表達:

 

 

 2.Java實體中的表達

 

 

 

 

 

 

 3.orm配置文件中的表達:(注意每次添加了ORM映射文件都要加到主配置文件中)

 User.hbm.xml

<?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">
   <!-- 配置表與實體對象的關系 -->
   <!-- package屬性:填寫一個包名.在元素內部凡是需要書寫完整類名的屬性,可以直接寫簡答類名了. -->
<hibernate-mapping package="cn.qlq.domain" >
    <!-- 
        class元素: 配置實體與表的對應關系的
            name: 完整類名
            table:數據庫表名
     -->
    <class name="User" table="sys_user" >
        <!-- id元素:配置主鍵映射的屬性
                name: 填寫主鍵對應屬性名
                column(可選): 填寫表中的主鍵列名.默認值:列名會默認使用屬性名
                type(可選):填寫列(屬性)的類型.hibernate會自動檢測實體的屬性類型.
                        每個類型有三種填法: java類型|hibernate類型|數據庫類型
                not-null(可選):配置該屬性(列)是否不能為空. 默認值:false
                length(可選):配置數據庫中列的長度. 默認值:使用數據庫類型的最大長度
         -->
        <id name="user_id"  >
            <!-- generator:主鍵生成策略 -->
            <!--identity : 主鍵自增.由數據庫來維護主鍵值.錄入時不需要指定主鍵.  -->
            <generator class="native"></generator>
        </id>
        <!-- property元素:除id之外的普通屬性映射
                name: 填寫屬性名
                column(可選): 填寫列名
                type(可選):填寫列(屬性)的類型.hibernate會自動檢測實體的屬性類型.
                        每個類型有三種填法: java類型|hibernate類型|數據庫類型
                not-null(可選):配置該屬性(列)是否不能為空. 默認值:false
                length(可選):配置數據庫中列的長度. 默認值:使用數據庫類型的最大長度
         -->
        <property name="User_name" length="20"/>
        <property name="user_state"/>
    
        <!-- 集合,多對多關系,在配置文件中配置 -->
        <!--  
            name:集合屬性名字
            table:中間表名
        -->
        <set name="roles" table="sys_user_role">
            <!-- column:外鍵,別人引用我的外鍵列名 -->
            <key column="user_id" ></key>
            <!-- class:我與哪個表是多對多關系,column:外鍵,我引用別人的外鍵 -->
            <many-to-many class="Role" column="role_id"></many-to-many>
        </set>
    </class>
</hibernate-mapping>

 

 

 Role.hbm.xml

<?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">
   <!-- 配置表與實體對象的關系 -->
   <!-- package屬性:填寫一個包名.在元素內部凡是需要書寫完整類名的屬性,可以直接寫簡答類名了. -->
<hibernate-mapping package="cn.qlq.domain" >
    <!-- 
        class元素: 配置實體與表的對應關系的
            name: 完整類名
            table:數據庫表名
     -->
    <class name="Role" table="sys_role" >
        <!-- id元素:配置主鍵映射的屬性
                name: 填寫主鍵對應屬性名
                column(可選): 填寫表中的主鍵列名.默認值:列名會默認使用屬性名
                type(可選):填寫列(屬性)的類型.hibernate會自動檢測實體的屬性類型.
                        每個類型有三種填法: java類型|hibernate類型|數據庫類型
                not-null(可選):配置該屬性(列)是否不能為空. 默認值:false
                length(可選):配置數據庫中列的長度. 默認值:使用數據庫類型的最大長度
         -->
        <id name="role_id"  >
            <!-- generator:主鍵生成策略 -->
            <!--identity : 主鍵自增.由數據庫來維護主鍵值.錄入時不需要指定主鍵.  -->
            <generator class="native"></generator>
        </id>
        <!-- property元素:除id之外的普通屬性映射
                name: 填寫屬性名
                column(可選): 填寫列名
                type(可選):填寫列(屬性)的類型.hibernate會自動檢測實體的屬性類型.
                        每個類型有三種填法: java類型|hibernate類型|數據庫類型
                not-null(可選):配置該屬性(列)是否不能為空. 默認值:false
                length(可選):配置數據庫中列的長度. 默認值:使用數據庫類型的最大長度
         -->
        <property name="role_name" length="20"/>
        <property name="role_state"/>
    
        <!-- 集合,多對多關系,在配置文件中配置 -->
        <!--  
            name:集合屬性名字
            table:中間表名
        -->
        <set name="users" table="sys_user_role">
            <!-- column:外鍵,別人引用我的外鍵列名 -->
            <key column="role_id" ></key>
            <!-- class:我與哪個表是多對多關系,column:外鍵,我引用別人的外鍵 -->
            <many-to-many class="User" column="user_id"></many-to-many>
        </set>
    </class>
</hibernate-mapping>

 

 

 4.測試建表結果:

     隨便執行一個hibernate測試,會加載主配置文件並進行建表。

mysql> desc sys_user;
+------------+-------------+------+-----+---------+----------------+
| Field      | Type        | Null | Key | Default | Extra          |
+------------+-------------+------+-----+---------+----------------+
| user_id    | bigint(20)  | NO   | PRI | NULL    | auto_increment |
| User_name  | varchar(20) | YES  |     | NULL    |                |
| user_state | char(1)     | YES  |     | NULL    |                |
+------------+-------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

mysql> desc sys_role;
+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| role_id    | bigint(20)   | NO   | PRI | NULL    | auto_increment |
| role_name  | varchar(20)  | YES  |     | NULL    |                |
| role_state | varchar(255) | YES  |     | NULL    |                |
+------------+--------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

mysql> desc sys_user_role;
+---------+------------+------+-----+---------+-------+
| Field   | Type       | Null | Key | Default | Extra |
+---------+------------+------+-----+---------+-------+
| user_id | bigint(20) | NO   | PRI | NULL    |       |
| role_id | bigint(20) | NO   | PRI | NULL    |       |
+---------+------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

 

 5.修改ORM配置中set元素配置對set元素的進一步解釋

 User.hbm.xml

 

 

 Role.hbm.xml

 

 

 修改之后查看建表語句:

mysql> show create table sys_user_role\G
*************************** 1. row ***************************
       Table: sys_user_role
Create Table: CREATE TABLE `sys_user_role` (
  `user_id1` bigint(20) NOT NULL,
  `role_id1` bigint(20) NOT NULL,
  PRIMARY KEY (`role_id1`,`user_id1`),
  KEY `FKgxeccay1ha1igqs2myct720lt` (`user_id1`),
  CONSTRAINT `FKgxeccay1ha1igqs2myct720lt` FOREIGN KEY (`user_id1`) REFERENCES `sys_user` (`user_id`)
  CONSTRAINT `FKtfvi95hnfedqqxi3rk1qmrwy7` FOREIGN KEY (`role_id1`) REFERENCES `sys_role` (`role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

 

 

 總結:

        <set name="users" table="sys_user_role">
            <!-- column:外鍵,別人引用我的外鍵列名 (可以簡單的理解為中間表的列名)-->
            <key column="role_id1" ></key>
            <!-- class:我與哪個表是多對多關系,column:外鍵,我引用別人的外鍵 -->
            <many-to-many class="User" column="user_id1"></many-to-many>
        </set>

 

  個人認為set元素更像是配置我與中間表的關系,key元素可以理解為中間表指向我的外鍵的名字,

    many-to-many中的class指的是與我是多對多的對象類名,column是在中間表中其對應的外鍵名字。

 

2.多對多操作

--------------------------第一次測試-----------------

1.測試保存:

    /**
     *測試保存(多對多)
     */
    @Test
    public void fun1() {
        //1.獲取session
        Session session = HibernateUtil.openSession();
        //2.開啟事務
        Transaction tx = session.beginTransaction();
        //3.構造數據(張三-總監、經理,李四---總監)
        User u1 = new User();
        u1.setUser_name("張三");
        User u2 = new User();
        u2.setUser_name("李四");
        
        Role r1 = new Role();
        r1.setRole_name("總監");
        Role r2 = new Role();
        r2.setRole_name("經理");
        
        u1.getRoles().add(r1);
        u1.getRoles().add(r2);
        u2.getRoles().add(r1);
        r1.getUsers().add(u1);
        r1.getUsers().add(u2);
        r2.getUsers().add(u1);
        
        session.save(u1);
        session.save(u2);
        session.save(r1);
        session.save(r1);
        //4.提交數據
        tx.commit();
        //5.關閉session
        session.close();
    }

 執行會報錯,因為兩個表都維護關系,所以會像中間表插入兩次記錄,導致插入重復。如下錯誤:

 

 解決辦法:

  •   第一鍾:將一方維護關系的代碼注釋掉:(一般開發中多對多的關系中都有一方放棄維護關系)

      

  • 第二種:配置文件中,設置一方放棄維護關系,例如:設置user放棄維護關系(一般開發中多對多的關系中都有一方放棄維護關系)

    

 

2.測試修改:

    /**
     *新增一個角色,並給張三新增加一個角色
     */
    @Test
    public void fun2() {
        //1.獲取session
        Session session = HibernateUtil.openSession();
        //2.開啟事務
        Transaction tx = session.beginTransaction();
        //3.構造數據(張三-總監、經理,李四---總監)
        User u1 = session.get(User.class, 1l);
        Role r3 = new Role();
        r3.setRole_name("太監");
        
        session.save(r3);//保存新角色
        
        u1.getRoles().add(r3);//u1處於持久態,因此不用執行更新語句也可以更新

        //4.提交數據
        tx.commit();
        //5.關閉session
        session.close();
    }

 

 

 3.測試給張三刪除一個角色

    /**
     *為張三刪除一個太監角色
     */
    @Test
    public void fun3() {
        //1.獲取session
        Session session = HibernateUtil.openSession();
        //2.開啟事務
        Transaction tx = session.beginTransaction();
        //3.構造數據(張三-總監、經理,李四---總監)
        User u1 = session.get(User.class, 1l);
        Role r1 = session.get(Role.class, 3l);
        
        
        u1.getRoles().remove(r1);//u1處於持久態,因此不用執行更新語句也可以更新

        //4.提交數據
        tx.commit();
        //5.關閉session
        session.close();
    }

 

 查看發出的SQL:

Hibernate: 
    select
        user0_.user_id as user_id1_3_0_,
        user0_.User_name as User_nam2_3_0_,
        user0_.user_state as user_sta3_3_0_ 
    from
        sys_user user0_ 
    where
        user0_.user_id=?
Hibernate: 
    select
        role0_.role_id as role_id1_2_0_,
        role0_.role_name as role_nam2_2_0_,
        role0_.role_state as role_sta3_2_0_ 
    from
        sys_role role0_ 
    where
        role0_.role_id=?
Hibernate: 
    select
        roles0_.user_id as user_id1_4_0_,
        roles0_.role_id as role_id2_4_0_,
        role1_.role_id as role_id1_2_1_,
        role1_.role_name as role_nam2_2_1_,
        role1_.role_state as role_sta3_2_1_ 
    from
        sys_user_role roles0_ 
    inner join
        sys_role role1_ 
            on roles0_.role_id=role1_.role_id 
    where
        roles0_.user_id=?
Hibernate: 
    delete 
    from
        sys_user_role 
    where
        user_id=? 
        and role_id=?

 

 

---------------------------第二次測試------------------

1.添加一個張三用戶,並給其添加兩個角色:經理和總監

    /**
     * 測試1:添加一個張三用戶
     * 添加兩個角色:經理、總監
     */
    @Test
    public void test1(){
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        
        /******S  開始業務邏輯*************/
        User u1 = new User();
        u1.setUser_name("張三");
        
        Role r1 = new Role();
        Role r2 = new Role();
        r1.setRole_name("總監");
        r2.setRole_name("經理");
        
        u1.getRoles().add(r1);
        u1.getRoles().add(r2);
        
        session.save(u1);
        session.save(r1);
        session.save(r2);
        /******E  開始業務邏輯*************/
        
        tx.commit();
        
    }

 

SQL:

Hibernate: 
    insert 
    into
        sys_user
        (user_name, user_state) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        sys_role
        (role_name, role_state) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        sys_role
        (role_name, role_state) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        sys_user_role
        (user_id, role_id) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        sys_user_role
        (user_id, role_id) 
    values
        (?, ?)

 

結果:

mysql> select * from sys_user;
+---------+-----------+------------+
| user_id | user_name | user_state |
+---------+-----------+------------+
|       1 | 張三      | NULL       |
+---------+-----------+------------+
1 row in set (0.03 sec)

mysql> select * from sys_role;
+---------+-----------+------------+
| role_id | role_name | role_state |
+---------+-----------+------------+
|       1 | 總監      | NULL       |
|       2 | 經理      | NULL       |
+---------+-----------+------------+
2 rows in set (0.00 sec)

mysql> select * from sys_user_role;
+---------+---------+
| user_id | role_id |
+---------+---------+
|       1 |       1 |
|       1 |       2 |
+---------+---------+
2 rows in set (0.00 sec)

 

 

2.給上面的張三解除與總監角色的關聯關系

    /**
     * 測試2:給上面的張三解除與總監角色的關聯關系
     */
    @Test
    public void test2(){
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        
        /******S  開始業務邏輯*************/
        //get方法獲取的對象都是持久態
        User user = session.get(User.class,1l );
        Role role = session.get(Role.class, 1l);
        user.getRoles().remove(role);
        /******E  開始業務邏輯*************/
        
        tx.commit();
    }

 

SQL:

Hibernate: 
    select
        user0_.user_id as user_id1_3_0_,
        user0_.user_name as user_nam2_3_0_,
        user0_.user_state as user_sta3_3_0_ 
    from
        sys_user user0_ 
    where
        user0_.user_id=?
Hibernate: 
    select
        role0_.role_id as role_id1_2_0_,
        role0_.role_name as role_nam2_2_0_,
        role0_.role_state as role_sta3_2_0_ 
    from
        sys_role role0_ 
    where
        role0_.role_id=?
Hibernate: 
    select
        roles0_.user_id as user_id1_4_0_,
        roles0_.role_id as role_id2_4_0_,
        role1_.role_id as role_id1_2_1_,
        role1_.role_name as role_nam2_2_1_,
        role1_.role_state as role_sta3_2_1_ 
    from
        sys_user_role roles0_ 
    inner join
        sys_role role1_ 
            on roles0_.role_id=role1_.role_id 
    where
        roles0_.user_id=?
Hibernate: 
    delete 
    from
        sys_user_role 
    where
        user_id=? 
        and role_id=?

 

結果:

mysql> select * from sys_user;
+---------+-----------+------------+
| user_id | user_name | user_state |
+---------+-----------+------------+
|       1 | 張三      | NULL       |
+---------+-----------+------------+
1 row in set (0.00 sec)

mysql> select * from sys_role;
+---------+-----------+------------+
| role_id | role_name | role_state |
+---------+-----------+------------+
|       1 | 總監      | NULL       |
|       2 | 經理      | NULL       |
+---------+-----------+------------+
2 rows in set (0.00 sec)

mysql> select * from sys_user_role;
+---------+---------+
| user_id | role_id |
+---------+---------+
|       1 |       2 |
+---------+---------+
1 row in set (0.00 sec)

 

 

3.刪除經理角色,同時刪除與張三的綁定關系

    /**
     * 測試3:刪除經理角色,同時刪除與張三的綁定關系
     */
    @Test
    public void test3(){
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        
        /******S  開始業務邏輯*************/
        //get方法獲取的對象都是持久態
        User user = session.get(User.class,1l );
        Role role = session.get(Role.class, 2l);
        session.delete(role);
        /******E  開始業務邏輯*************/
        
        tx.commit();
    }

 

SQL:

Hibernate: 
    select
        user0_.user_id as user_id1_3_0_,
        user0_.user_name as user_nam2_3_0_,
        user0_.user_state as user_sta3_3_0_ 
    from
        sys_user user0_ 
    where
        user0_.user_id=?
Hibernate: 
    select
        role0_.role_id as role_id1_2_0_,
        role0_.role_name as role_nam2_2_0_,
        role0_.role_state as role_sta3_2_0_ 
    from
        sys_role role0_ 
    where
        role0_.role_id=?
Hibernate: 
    delete 
    from
        sys_user_role 
    where
        role_id=?
Hibernate: 
    delete 
    from
        sys_role 
    where
        role_id=?

 

結果:

mysql> select * from sys_role;
+---------+-----------+------------+
| role_id | role_name | role_state |
+---------+-----------+------------+
|       1 | 總監      | NULL       |
+---------+-----------+------------+
1 row in set (0.00 sec)

mysql> select * from sys_user_role;
Empty set (0.00 sec)

 

 

4.新增一個秘書角色,並賦給張三該角色

    /**
     * 測試4:新增一個秘書角色,並賦給張三該角色
     */
    @Test
    public void test4(){
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        
        /******S  開始業務邏輯*************/
        //get方法獲取的對象都是持久態
        Role r1 = new Role();
        r1.setRole_name("秘書");
        User user = session.get(User.class,1l);
        user.getRoles().add(r1);
        
        session.save(r1);
        session.update(user);
        /******E  開始業務邏輯*************/
        
        tx.commit();
    }

 

SQL:

Hibernate: 
    select
        user0_.user_id as user_id1_3_0_,
        user0_.user_name as user_nam2_3_0_,
        user0_.user_state as user_sta3_3_0_ 
    from
        sys_user user0_ 
    where
        user0_.user_id=?
Hibernate: 
    select
        roles0_.user_id as user_id1_4_0_,
        roles0_.role_id as role_id2_4_0_,
        role1_.role_id as role_id1_2_1_,
        role1_.role_name as role_nam2_2_1_,
        role1_.role_state as role_sta3_2_1_ 
    from
        sys_user_role roles0_ 
    inner join
        sys_role role1_ 
            on roles0_.role_id=role1_.role_id 
    where
        roles0_.user_id=?
Hibernate: 
    insert 
    into
        sys_role
        (role_name, role_state) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        sys_user_role
        (user_id, role_id) 
    values
        (?, ?)

 

結果:

mysql> select * from sys_role;
+---------+-----------+------------+
| role_id | role_name | role_state |
+---------+-----------+------------+
|       1 | 總監      | NULL       |
|       3 | 秘書      | NULL       |
+---------+-----------+------------+
2 rows in set (0.00 sec)

mysql> select * from sys_user_role;
+---------+---------+
| user_id | role_id |
+---------+---------+
|       1 |       3 |
+---------+---------+
1 row in set (0.00 sec)

 

 

5.修改秘書角色為總監秘書(不影響與用戶的關聯)

    /**
     * 測試5:修改秘書角色為總監秘書(不影響與用戶的關聯)
     */
    @Test
    public void test5(){
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        
        /******S  開始業務邏輯*************/
        //get方法獲取的對象都是持久態
        Role role = session.get(Role.class,3l);
        role.setRole_name("總監秘書");
        session.update(role);
        /******E  開始業務邏輯*************/
        
        tx.commit();
    }

 

SQL:

Hibernate: 
    select
        role0_.role_id as role_id1_2_0_,
        role0_.role_name as role_nam2_2_0_,
        role0_.role_state as role_sta3_2_0_ 
    from
        sys_role role0_ 
    where
        role0_.role_id=?
Hibernate: 
    update
        sys_role 
    set
        role_name=?,
        role_state=? 
    where
        role_id=?

 

結果:

mysql> select * from sys_user_role;
+---------+---------+
| user_id | role_id |
+---------+---------+
|       1 |       3 |
+---------+---------+
1 row in set (0.00 sec)

mysql> select * from sys_role;
+---------+-----------+------------+
| role_id | role_name | role_state |
+---------+-----------+------------+
|       1 | 總監      | NULL       |
|       3 | 總監秘書  | NULL       |
+---------+-----------+------------+
2 rows in set (0.00 sec)

 

 

6.刪除一個用戶,會自動刪除中間表

mysql> select * from sys_user_role;
+---------+---------+
| user_id | role_id |
+---------+---------+
|       1 |       3 |
+---------+---------+
1 row in set (0.00 sec)

mysql> select * from sys_role;
+---------+-----------+------------+
| role_id | role_name | role_state |
+---------+-----------+------------+
|       1 | 總監      | NULL       |
|       3 | 總監秘書  | NULL       |
+---------+-----------+------------+
2 rows in set (0.00 sec)

 

SQL:

Hibernate: 
    select
        user0_.user_id as user_id1_3_0_,
        user0_.user_name as user_nam2_3_0_,
        user0_.user_state as user_sta3_3_0_ 
    from
        sys_user user0_ 
    where
        user0_.user_id=?
Hibernate: 
    delete 
    from
        sys_user_role 
    where
        user_id=?
Hibernate: 
    delete 
    from
        sys_user 
    where
        user_id=?

 

結果:

mysql> select * from sys_user;
Empty set (0.00 sec)

mysql> select * from sys_role;
+---------+-----------+------------+
| role_id | role_name | role_state |
+---------+-----------+------------+
|       1 | 總監      | NULL       |
|       3 | 總監秘書  | NULL       |
+---------+-----------+------------+
2 rows in set (0.00 sec)

mysql> select * from sys_user_role;
Empty set (0.00 sec)

 

 

3.進階操作

1.inverse屬性:

   一般開發中遇到多對多的關系總有一方放棄維護關系,至於是哪一方要看具體的業務需求。可以在代碼中放棄維護,也可以在配置文件中放棄維護。例如錄入員工時需要為員工指定所屬角色,那么業務方向就是由員工維護角色,角色不需要維護與員工的關系。

  • 代碼中放棄維護角色:
    /**
     *測試保存(多對多)
     */
    @Test
    public void fun1() {
        //1.獲取session
        Session session = HibernateUtil.openSession();
       //2.開啟事務
        Transaction tx = session.beginTransaction();
        //3.構造數據(張三-總監、經理,李四---總監)
        User u1 = new User();
        u1.setUser_name("張三");
        User u2 = new User();
        u2.setUser_name("李四");
        
        Role r1 = new Role();
        r1.setRole_name("總監");
        Role r2 = new Role();
        r2.setRole_name("經理");
        
        u1.getRoles().add(r1);
        u1.getRoles().add(r2);
        u2.getRoles().add(r1);
        //角色放棄維護與員工的關系
//        r1.getUsers().add(u1);
//        r1.getUsers().add(u2);
//        r2.getUsers().add(u1);
        
        session.save(r1);
        session.save(r2);
        session.save(u1);
        session.save(u2);
        //4.提交數據
        tx.commit();
        //5.關閉session
        session.close();
    }

 

 

  • Role.hbm.xml配置文件中放棄維護關系inverse屬性為true即是放棄維護關系

 

2.級聯操作  cascade屬性

save-update :級聯保存或更新

delete:級聯刪除

all:等於save-update+delete

 

1.級聯保存或者更新:

  例如我們新增一個角色並且給張三賦予新角色的代碼如下:

    @Test
    public void fun2() {
        //1.獲取session
        Session session = HibernateUtil.openSession();
        //2.開啟事務
        Transaction tx = session.beginTransaction();
        //3.構造數據(張三-總監、經理,李四---總監)
        User u1 = session.get(User.class, 1l);
        Role r3 = new Role();
        r3.setRole_name("太監222");
        
        session.save(r3);//保存新角色
        
        u1.getRoles().add(r3);//u1處於持久態,因此不用執行更新語句也可以更新

        //4.提交數據
        tx.commit();
        //5.關閉session
        session.close();
    }

 

 我們希望在更新user的時候會級聯保存角色,也就是省區一行session.save(r3)對象。

(1)修改User.hbm.xml

 

 (2)將代碼保存角色的那一行代碼注釋掉

 

(3)測試並查看SQL:

Hibernate: 
    select
        user0_.user_id as user_id1_3_0_,
        user0_.User_name as User_nam2_3_0_,
        user0_.user_state as user_sta3_3_0_ 
    from
        sys_user user0_ 
    where
        user0_.user_id=?
Hibernate: 
    select
        roles0_.user_id as user_id1_4_0_,
        roles0_.role_id as role_id2_4_0_,
        role1_.role_id as role_id1_2_1_,
        role1_.role_name as role_nam2_2_1_,
        role1_.role_state as role_sta3_2_1_ 
    from
        sys_user_role roles0_ 
    inner join
        sys_role role1_ 
            on roles0_.role_id=role1_.role_id 
    where
        roles0_.user_id=?
Hibernate: 
    insert 
    into
        sys_role
        (role_name, role_state) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        sys_user_role
        (user_id, role_id) 
    values
        (?, ?)

 

2.級聯刪除:

修改User.hbm.xml,開啟級聯刪除:

 

 

測試代碼:(會級聯去刪除角色表,如果角色表對應記錄被其他用戶引用會報錯)

    /**
     *刪除張三,查看級聯刪除角色
     */
    @Test
    public void fun4() {
        //1.獲取session
        Session session = HibernateUtil.openSession();
        //2.開啟事務
        Transaction tx = session.beginTransaction();
        //3.構造數據(張三-總監、經理,李四---總監)
        User u1 = session.get(User.class, 5l);
        session.delete(u1);
        
        //4.提交數據
        tx.commit();
        //5.關閉session
        session.close();
    }

 

查看發出的SQL:

 

Hibernate: 
    select
        user0_.user_id as user_id1_3_0_,
        user0_.User_name as User_nam2_3_0_,
        user0_.user_state as user_sta3_3_0_ 
    from
        sys_user user0_ 
    where
        user0_.user_id=?
Hibernate: 
    select
        roles0_.user_id as user_id1_4_0_,
        roles0_.role_id as role_id2_4_0_,
        role1_.role_id as role_id1_2_1_,
        role1_.role_name as role_nam2_2_1_,
        role1_.role_state as role_sta3_2_1_ 
    from
        sys_user_role roles0_ 
    inner join
        sys_role role1_ 
            on roles0_.role_id=role1_.role_id 
    where
        roles0_.user_id=?
Hibernate: 
    delete 
    from
        sys_user_role 
    where
        user_id=?
Hibernate: 
    delete 
    from
        sys_role 
    where
        role_id=?
Hibernate: 
    delete 
    from
        sys_role 
    where
        role_id=?
Hibernate: 
    delete 
    from
        sys_user 
    where
        user_id=?

 

總結:

    O 對象            兩方都使用集合. 
    R 關系型數據庫    使用中間表.至少兩列.作為外鍵引用兩張表的主鍵.
    M 映射文件        多: <set name="" table="中間表名" >
                            <key column="別人引用我" />
                            <man-to-many class="" column="我引用別人的" />
                        </set>
                        
    操作:操作管理級別屬性. 
        cascade: 級聯操作    
            減少我們書寫的操作代碼.
            none(默認值)    不級聯
            save-update:    級聯保存
            delete:            級聯刪除
            all:            級聯保存+級聯刪除
        結論: 可以使用save-update.不推薦使用delete. 也可以不用cascade.
        inverse: 反轉關系維護
            屬於性能優化.必須選擇一方放棄維護主鍵關系.哪方放棄要看業務方向.

 

補充:多對多的時候經常用到查詢,比如上面查詢用戶ID為1的用戶具有的角色

  用HQL判斷兩個實體間是否存在一對多關系,用的  in elements, 注意in elements 只能用於where 從句中

語法如下:

    @Test
    public void fun5() {
        // 1.獲取session
        Session session = HibernateUtil.openSession();

        String hql = "from Role r where ? in elements(r.users)";
        Query query = session.createQuery(hql);

        User user = new User();
        user.setUser_id(1L);
        query.setParameter(0, user);

        List<Role> roles = query.list();
        System.out.println(roles);
    }

查看SQL語句如下:

Hibernate:
select
role0_.role_id as role_id1_0_,
role0_.role_name as role_nam2_0_,
role0_.role_state as role_sta3_0_
from
sys_role role0_
where
? in (
select
users1_.user_id
from
sys_user_role users1_
where
role0_.role_id=users1_.role_id
)
Hibernate:
select
users0_.role_id as role_id2_2_0_,
users0_.user_id as user_id1_2_0_,
user1_.user_id as user_id1_1_1_,
user1_.User_name as User_nam2_1_1_,
user1_.user_state as user_sta3_1_1_
from
sys_user_role users0_
inner join
sys_user user1_
on users0_.user_id=user1_.user_id
where
users0_.role_id=?
Hibernate:
select
users0_.role_id as role_id2_2_0_,
users0_.user_id as user_id1_2_0_,
user1_.user_id as user_id1_1_1_,
user1_.User_name as User_nam2_1_1_,
user1_.user_state as user_sta3_1_1_
from
sys_user_role users0_
inner join
sys_user user1_
on users0_.user_id=user1_.user_id
where
users0_.role_id=?

 


免責聲明!

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



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