Hibernate框架筆記03_表操作_多對多配置

Hibernate框架筆記03_表操作_多對多配置

思維導(dǎo)圖

1. 數(shù)據(jù)庫表與表之間的關(guān)系

1.1 一對多關(guān)系

  • 什么樣的關(guān)系屬于一對多航徙?

    • 一個部門對應(yīng)多個員工,一個員工只能屬于某一個部門
    • 一個客戶對應(yīng)多個聯(lián)系人持际,一個聯(lián)系人只能屬于某一個客戶
  • 一對多的建表原則:在多的一方創(chuàng)建外鍵指向一的一方的主鍵

    一對多建表原則

1.2 多對多關(guān)系

  • 什么樣的關(guān)系屬于多對多?

    • 一個學(xué)生可以選擇多門課程,一門課程可以被多個學(xué)生選擇
    • 一個用戶可以選擇多個角色玻佩,一個角色可以被多個用戶選擇
  • 多對多的建表原則:多對多建原則:創(chuàng)建一個中間表荷科,中間表至少有兩個字段分別作為外鍵指向多對多雙方的主鍵唯咬。

    多對多建表原則

1.3 一對一關(guān)系【了解】

  • 什么樣的關(guān)系屬于一對一?
    • 一個公司只能有一個注冊地址畏浆,一個注冊地址只能被一個公司注冊胆胰。
  • 唯一外鍵對應(yīng):假設(shè)是一對多的關(guān)系,需要在多的一方創(chuàng)建外鍵指向一的一方的主鍵刻获,將外鍵設(shè)置為unique
  • 主鍵對應(yīng):讓某個表的主鍵作為另一個表的主鍵蜀涨。

2. Hibernate的一對多關(guān)聯(lián)映射

2.1 創(chuàng)建一個項目,引入相關(guān)jar包

相關(guān)jar包

2.2. 創(chuàng)建數(shù)據(jù)庫和表

  • 創(chuàng)建數(shù)據(jù)庫蝎毡,新建兩張表

  • customer表crm_cst_customer.sql

    CREATE TABLE `cst_customer` (
      `cust_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客戶編號(主鍵)',
      `cust_name` varchar(32) NOT NULL COMMENT '客戶名稱(公司名稱)',
      `cust_source` varchar(32) DEFAULT NULL COMMENT '客戶信息來源',
      `cust_industry` varchar(32) DEFAULT NULL COMMENT '客戶所屬行業(yè)',
      `cust_level` varchar(32) DEFAULT NULL COMMENT '客戶級別',
      `cust_phone` varchar(64) DEFAULT NULL COMMENT '固定電話',
      `cust_mobile` varchar(16) DEFAULT NULL COMMENT '移動電話',
      PRIMARY KEY (`cust_id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
    
  • LinkMan表crm_cst_linkman.sql

    
    CREATE TABLE `cst_linkman` (
      `lkm_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '聯(lián)系人編號(主鍵)',
      `lkm_name` varchar(16) DEFAULT NULL COMMENT '聯(lián)系人姓名',
      `lkm_cust_id` bigint(32) NOT NULL COMMENT '客戶id',
      `lkm_gender` char(1) DEFAULT NULL COMMENT '聯(lián)系人性別',
      `lkm_phone` varchar(16) DEFAULT NULL COMMENT '聯(lián)系人辦公電話',
      `lkm_mobile` varchar(16) DEFAULT NULL COMMENT '聯(lián)系人手機',
      `lkm_email` varchar(64) DEFAULT NULL COMMENT '聯(lián)系人郵箱',
      `lkm_qq` varchar(16) DEFAULT NULL COMMENT '聯(lián)系人qq',
      `lkm_position` varchar(16) DEFAULT NULL COMMENT '聯(lián)系人職位',
      `lkm_memo` varchar(512) DEFAULT NULL COMMENT '聯(lián)系人備注',
      PRIMARY KEY (`lkm_id`),
      KEY `FK_cst_linkman_lkm_cust_id` (`lkm_cust_id`),
      CONSTRAINT `FK_cst_linkman_lkm_cust_id` FOREIGN KEY (`lkm_cust_id`) REFERENCES `cst_customer` (`cust_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
    ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
    
  • 兩個表之間的關(guān)系

兩個表之間的關(guān)系

2.3 創(chuàng)建實體

  public class Customer {
    private Long cust_id;
    private String cust_name;
    private String cust_source;
    private String cust_industry;
    private String cust_level;
    private String cust_phone;
    private String cust_mobile;
    // 通過ORM方式表示:一個客戶對應(yīng)多個聯(lián)系人
    // 放置的是多的一方的集合厚柳。Hibernate默認(rèn)使用的是Set集合
    private Set<LinkMan> linkMans = new HashSet<LinkMan>();
    
    //get/set方法
public class LinkMan {
  private Long lkm_id;
  private String lkm_name;
  private String lkm_gender;
  private String lkm_phone;
  private String lkm_mobile;
  private String lkm_email;
  private String lkm_qq;
  private String lkm_position;
  private String lkm_memo;
  // 通過ORM方式表示:一個聯(lián)系人只能屬于某一個客戶
  // 放置的是一的一方的對象
  private Customer customer;
  //set/get方法

2.4 創(chuàng)建映射文件

  • 有幾個實體就需要幾個映射文件

  • Customer.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">
        
    <hibernate-mapping>
      <class name="com.itzhouq.hibernate.domain.Customer" table="cst_customer">
          <!-- 建立OID與主鍵映射 -->
          <id name="cust_id" column="cust_id">
              <generator class="native"></generator>
          </id>
          <!-- 建立普通屬性和數(shù)據(jù)庫字段映射 -->
          <property name="cust_name" column="cust_name"></property>
          <property name="cust_source" column="cust_source"></property>
          <property name="cust_industry" column="cust_industry"></property>
          <property name="cust_level" column="cust_level"></property>
          <property name="cust_phone" column="cust_phone"></property>
          <property name="cust_mobile" column="cust_mobile"></property>
          
          <!-- 配置一對多的映射:放置的多的一方的集合 -->
          <!-- 
              set標(biāo)簽:
                  * name:多的一方的對象集合的屬性名稱
           -->
          <set name="linkMans">
              <!-- column多的一方的外鍵的名稱 -->
              <key column="lkm_cust_id"></key>
              <!-- class:多的一方的類的全限定名 -->
              <one-to-many class="com.itzhouq.hibernate.domain.LinkMan"/>
          </set>
      </class>
    </hibernate-mapping>
    
  • LinkMan.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">
        
    <hibernate-mapping>
      <class name="com.itzhouq.hibernate.domain.LinkMan" table="cst_linkman">
          <!-- 建立OID與主鍵映射 -->
          <id name="lkm_id" column="lkm_id">
              <generator class="native"></generator>
          </id>
          
          <!-- 建立普通屬性與表字段映射 -->
          <property name="lkm_name"/>
          <property name="lkm_gender"/>
          <property name="lkm_phone"/>
          <property name="lkm_mobile"/>
          <property name="lkm_email"/>
          <property name="lkm_qq"/>
          <property name="lkm_position"/>
          <property name="lkm_memo"/>
          
          <!-- 配置多對一的關(guān)系:放置的是一的一方的對象 -->
          <!-- 
              many-to-one標(biāo)簽
                  * name:一的一方的對象的屬性名稱
                  *class:一的一方的類的全限定名
                  column:在多的一方的表的外鍵的名稱
           -->
           <many-to-one name="customer" class="com.itzhouq.hibernate.domain.Customer" column="lkm_cust_id"/>
      </class>
    </hibernate-mapping>
    

2.5 創(chuàng)建核心配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <!-- 連接數(shù)據(jù)庫的基本參數(shù) -->
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql:///hibernate_day03</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password">2626</property>
        
        <!-- 配置Hibernate的方言(可選的) -->
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
        <!-- 打印SQL(可選的) -->
        <property name="hibernate.show_sql">true</property>
        <!-- 格式化SQL(可選的) -->
        <property name="hibernate.format_sql">true</property>
        <!-- 自動創(chuàng)建表 -->
        <property name="hibernate.hbm2ddl.auto">update</property>
        
        <!-- 配置C3P0連接池 -->
        <property name="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
        <!--在連接池中可用的數(shù)據(jù)庫連接的最少數(shù)目 -->
        <property name="c3p0.min_size">5</property>
        <!--在連接池中所有數(shù)據(jù)庫連接的最大數(shù)目  -->
        <property name="c3p0.max_size">20</property>
        <!--設(shè)定數(shù)據(jù)庫連接的過期時間,以秒為單位,
        如果連接池中的某個數(shù)據(jù)庫連接處于空閑狀態(tài)的時間超過了timeout時間,就會從連接池中清除 -->
        <property name="c3p0.timeout">120</property>
         <!--每3000秒檢查所有連接池中的空閑連接 以秒為單位-->
        <property name="c3p0.idle_test_period">3000</property>
        
        <!-- 設(shè)置事務(wù)的隔離級別 -->
        <property name="hibernate.connection.isolation">4</property>
        
        <!-- 配置當(dāng)前線程綁定的Session -->
        <property name="hibernate.current_session_context_class">thread</property>
        
        <!-- 配置映射文件 -->
        <mapping resource="com/itzhouq/hibernate/domain/Customer.hbm.xml"/>
        <mapping resource="com/itzhouq/hibernate/domain/LinkMan.hbm.xml"/>
        
    </session-factory>
</hibernate-configuration>

2.6 引入工具類和日志

2.7 編寫測試

package com.itzhouq.hibernate.demo;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import com.itzhouq.hibernate.domain.Customer;
import com.itzhouq.hibernate.domain.LinkMan;
import com.itzhouq.hibernate.utils.HibernateUtils;

/*
 * 一對多的測試類
 */
public class Demo1 {
    @Test
    // 保存兩個聯(lián)系人,三個客戶
    public void test() {
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        // 創(chuàng)建兩個客戶
        Customer customer1 = new Customer();
        customer1.setCust_name("王東");
        Customer customer2 = new Customer();
        customer2.setCust_name("李希");
        
        // 創(chuàng)建三個聯(lián)系人
        LinkMan linkMan1 = new LinkMan();
        linkMan1.setLkm_name("鳳姐");
        LinkMan linkMan2 = new LinkMan();
        linkMan2.setLkm_name("如花");
        LinkMan linkMan3 = new LinkMan();
        linkMan3.setLkm_name("王冬冬");
        
        // 設(shè)置關(guān)系
        linkMan1.setCustomer(customer1);
        linkMan2.setCustomer(customer1);
        linkMan3.setCustomer(customer2);
        customer1.getLinkMans().add(linkMan1);
        customer1.getLinkMans().add(linkMan2);
        customer2.getLinkMans().add(linkMan3);
        
        // 保存數(shù)據(jù)
        session.save(customer1);
        session.save(customer2);
        session.save(linkMan1);
        session.save(linkMan2);
        session.save(linkMan3);
        
        transaction.commit();
    }
}

2.8 一對多的級聯(lián)操作

  • 級聯(lián):級聯(lián)指的是沐兵,操作一個對象時草娜,是否會同時操作其關(guān)聯(lián)的對象。
  • 級聯(lián)是有方向性:
    • 操作一的一方的時候痒筒,是否操作到多的一方
    • 操作多的一方的時候宰闰,是否操作到一的一方

2.8.1 級聯(lián)保存或級聯(lián)刪除

  • 保存客戶茬贵,級聯(lián)聯(lián)系人

    • 操作的主體是客戶對象,需要在Customer.hbm.xml中進(jìn)行配置
    <!-- 
              set標(biāo)簽:
                  * name:多的一方的對象集合的屬性名稱
                  * cascade:級聯(lián)
           -->
          <set name="linkMans" cascade="save-update">
              <!-- column多的一方的外鍵的名稱 -->
              <key column="lkm_cust_id"></key>
              <!-- class:多的一方的類的全限定名 -->
              <one-to-many class="com.itzhouq.hibernate.domain.LinkMan"/>
          </set>
    
@Test
  /**
   *  級聯(lián)保存或更新操作
   *  保存客戶級聯(lián)聯(lián)系人,操作的主體是客戶對象移袍,需要在Customer.hbm.xml中進(jìn)行配置
   */
  public void test2() {
      Session session = HibernateUtils.getCurrentSession();
      Transaction transaction = session.beginTransaction();
      Customer customer = new Customer();
      customer.setCust_name("趙紅");
      
      LinkMan linkMan = new LinkMan();
      linkMan.setLkm_name("如花");
      
      customer.getLinkMans().add(linkMan);
      linkMan.setCustomer(customer);
      session.save(customer);
      
      transaction.commit();
      
  }
  • 保存聯(lián)系人解藻,級聯(lián)客戶

    • 操作的主體是聯(lián)系人對象,需要在LinkMan.hbm.xml中進(jìn)行配置

      <many-to-one name="customer" cascade="save-update" class="com.itzhouq.hibernate.domain.Customer" column="lkm_cust_id"/>
      
      @Test
          /**
           *  級聯(lián)保存或更新操作
           *  保存客戶級聯(lián)聯(lián)系人,操作的主體是客戶對象葡盗,需要在LinkMan.hbm.xml中進(jìn)行配置
           */
          public void test2() {
              Session session = HibernateUtils.getCurrentSession();
              Transaction transaction = session.beginTransaction();
              Customer customer = new Customer();
              customer.setCust_name("趙斌");
              
              LinkMan linkMan = new LinkMan();
              linkMan.setLkm_name("思域");
              
              customer.getLinkMans().add(linkMan);
              linkMan.setCustomer(customer);
              session.save(linkMan);
              
              transaction.commit();
              
          }
      
  • 測試對象導(dǎo)航

    @Test
      /**
       *  測試對象的導(dǎo)航
       *  前提:一對多的雙方都設(shè)置cascade="save-update"
       */
      public void test3() {
          Session session = HibernateUtils.getCurrentSession();
          Transaction transaction = session.beginTransaction();
          Customer customer = new Customer();
          customer.setCust_name("趙斌");
          
          LinkMan linkMan1 = new LinkMan();
          linkMan1.setLkm_name("鳳姐");
          LinkMan linkMan2 = new LinkMan();
          linkMan2.setLkm_name("如花");
          LinkMan linkMan3 = new LinkMan();
          linkMan3.setLkm_name("芙蓉");
          
          linkMan1.setCustomer(customer);
          customer.getLinkMans().add(linkMan2);
          customer.getLinkMans().add(linkMan3);
          
          // 雙方都設(shè)置了cascade
          //session.save(linkMan1);   // 發(fā)送幾條insert語句     4條
          //session.save(customer);   // 發(fā)送幾條insert語句     3條
          session.save(linkMan2); // 發(fā)送幾條insert語句     1條
          
          transaction.commit();
          
      }
    

2.8.2 級聯(lián)刪除

  • 級聯(lián)刪除:級聯(lián)刪除一遍的時候螟左,同時將另一方的數(shù)據(jù)也一并刪除

  • 刪除客戶的時候級聯(lián)刪除聯(lián)系人

  • 刪除的主體是客戶,需要在Custoemr.hbm.xml中配置

    <set name="linkMans" cascade="save-update,delete">
              <!-- column多的一方的外鍵的名稱 -->
              <key column="lkm_cust_id"></key>
              <!-- class:多的一方的類的全限定名 -->
              <one-to-many class="com.itzhouq.hibernate.domain.LinkMan"/>
          </set>
    
@Test
  /**
   *  級聯(lián)刪除
   *  刪除客戶級聯(lián)刪除聯(lián)系人觅够,刪除的主體是客戶胶背,需要在Custoemr.hbm.xml中配置
   */
  public void test4() {
      Session session = HibernateUtils.getCurrentSession();
      Transaction transaction = session.beginTransaction();
      
      // 沒有設(shè)置級聯(lián),默認(rèn)情況:修改聯(lián)系人的外鍵喘先,刪除客戶
      //Customer customer = session.get(Customer.class, 1L);
      //session.delete(customer);
      
      // 刪除客戶钳吟,同時刪除聯(lián)系人 <set name="linkMans" cascade="save-update,delete">
      Customer customer = session.get(Customer.class, 1L);
      session.delete(customer);
      transaction.commit();
      
  }
  • 刪除聯(lián)系人級聯(lián)刪除客戶(基本不用)

2.8.3 inverse的配置

  • 一對多設(shè)置了雙向關(guān)聯(lián)會產(chǎn)生多余的SQL語句

    @Test
      /**
       *  將2號聯(lián)系人原來歸1號聯(lián)系人,現(xiàn)在改為2號客戶
       */
      public void test5() {
          Session session = HibernateUtils.getCurrentSession();
          Transaction transaction = session.beginTransaction();
          // 查詢2號聯(lián)系人
          LinkMan linkMan = session.get(LinkMan.class, 2L);
          
          //查詢2號客戶
          Customer customer = session.get(Customer.class, 2L);
          
          //雙向的關(guān)聯(lián)
          linkMan.setCustomer(customer);
          customer.getLinkMans().add(linkMan);
          //發(fā)送了兩次update語句窘拯,對外鍵修改了兩次
          
          //持久態(tài)對象自動更新
          
          transaction.commit();
      }
    
  • 分析

    雙向維護(hù)
  • 解決多余的SQL語句

    • 單向維護(hù)
    • 使一方放棄外鍵維護(hù)權(quán):一的一方放棄红且。在配置文件Customer.hbm.xml中的set上配置inverse="true"
  • 區(qū)分cascade和inverse

    • cascade是操作關(guān)聯(lián)對象的,比如客戶存到數(shù)據(jù)庫了涤姊,客戶關(guān)聯(lián)的聯(lián)系人也會存到數(shù)據(jù)庫

    • 但是有沒有外鍵是由inverse控制的

      @Test
          /**
           *  區(qū)分cascade和inverse的區(qū)別
           */
          public void test6() {
              Session session = HibernateUtils.getCurrentSession();
              Transaction transaction = session.beginTransaction();
              Customer customer = new Customer();
              customer.setCust_name("李斌");
              
              LinkMan linkMan = new LinkMan();
              linkMan.setLkm_name("鳳姐");      
              
              customer.getLinkMans().add(linkMan);
              
              //條件在Customer.hbm.xml上的set中配置了cascade="save-update" inverse="true"
              session.save(customer); // 客戶回插入到數(shù)據(jù)庫暇番,聯(lián)系人也會插入到數(shù)據(jù)庫,但是外鍵為null
              transaction.commit();
          }
      

      Customer.hbm.xml相關(guān)配置

      <!-- 
                  set標(biāo)簽:
                      * name:多的一方的對象集合的屬性名稱
                      * cascade:級聯(lián)
                      * inverse: 是否放棄外鍵約束思喊,true表示放棄外鍵約束
               -->
              <set name="linkMans" cascade="save-update,delete" inverse="true">
                  <!-- column多的一方的外鍵的名稱 -->
                  <key column="lkm_cust_id"></key>
                  <!-- class:多的一方的類的全限定名 -->
                  <one-to-many class="com.itzhouq.hibernate.domain.LinkMan"/>
              </set>
      

3. Hibernate的多對多關(guān)聯(lián)映射

3.1 HIbernate多對多的關(guān)系的配置

3.1.1 創(chuàng)建表

  • 用戶表
CREATE TABLE `sys_user` (
  `user_id` BIGINT(32) NOT NULL AUTO_INCREMENT COMMENT '用戶id',
  `user_code` VARCHAR(32) COMMENT '用戶賬號',
  `user_name` VARCHAR(64) COMMENT '用戶名稱',
  `user_password` VARCHAR(32) COMMENT '用戶密碼',
  `user_state` CHAR(1) COMMENT '1:正常,0:暫停',
  PRIMARY KEY (`user_id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
  • 角色表
CREATE TABLE `sys_role` (
  `role_id` BIGINT(32) NOT NULL AUTO_INCREMENT,
  `role_name` VARCHAR(32) COMMENT '角色名稱',
  `role_memo` VARCHAR(128) DEFAULT NULL COMMENT '備注',
  PRIMARY KEY (`role_id`)
) ENGINE=INNODB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
  • 中間表
CREATE TABLE `sys_user_role` (
  `role_id` BIGINT(32) NOT NULL COMMENT '角色id',
  `user_id` BIGINT(32) NOT NULL COMMENT '用戶id',
  PRIMARY KEY (`role_id`,`user_id`),
  KEY `FK_user_role_user_id` (`user_id`),
  CONSTRAINT `FK_user_role_role_id` FOREIGN KEY (`role_id`) REFERENCES `sys_role` (`role_id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  CONSTRAINT `FK_user_role_user_id` FOREIGN KEY (`user_id`) REFERENCES `sys_user` (`user_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=INNODB DEFAULT CHARSET=utf8;
表之間的關(guān)系

3.1.2 創(chuàng)建實體

  • 用戶實體User
public class User {
    private Long user_id;
    private String user_code;
    private String user_name;
    private String user_password;
    private String user_state;
    // 設(shè)置多對多關(guān)系:表示一個用戶選擇多個角色
    // 放置的是角色的集合
    private Set<Role> roles = new HashSet<Role>();
    //set/get方法
  • 角色實體Role
public class Role {
    private Long role_id;
    private String role_name;
    private String role_memo;
    
    // 一個角色被多個用戶選擇
    // 放置的是用戶的集合
    private Set<User> users = new HashSet<User>();
    //set/get方法

3.1.3 創(chuàng)建映射

  • 用戶的映射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">
    
<hibernate-mapping>
    <class name="com.itzhouq.hibernate.domain.User" table="sys_user">
        <!-- 建立主鍵與OID的映射 -->
        <id name="user_id" column="user_id">
            <generator class="native"/>
        </id>
        <!-- 建立普通屬性與字段映射 -->
        <property name="user_code" column="user_code"/>
        <property name="user_name" column="user_name"/>
        <property name="user_password" column="user_password"/>
        <property name="user_state" column="user_state"/>
        
        <!-- 建立角色的多對多的映射關(guān)系-->
        <!-- set
            * name:對方的集合的屬性名
            * table:多對多的關(guān)系需要使用中間表壁酬,放的是中間表的名稱。
         -->
        <set name="roles" table="sys_user_role">
            <!-- key標(biāo)簽中column指的是當(dāng)前對象對應(yīng)的中間表的外鍵的名稱 -->
            <!-- many-to-many標(biāo)簽:
                * class : 對方的類的全路徑
                * column : 對方的對象在中間表中的外鍵的名稱
             -->
            <key column="user_id"/>
            <many-to-many class="com.itzhouq.hibernate.domain.Role" column="role_id"/>
        </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">
   
<hibernate-mapping>
    <class name="com.itzhouq.hibernate.domain.Role" table="sys_role">
        <!-- 建立主鍵與OID的屬性 -->
        <id name="role_id" column="role_id">
            <generator class="native"/>
        </id>
        <!-- 將普通屬性與字段映射-->
        <property name="role_name" column="role_name"/>
        <property name="role_memo" column="role_memo"/>
        <!--inverse="true",Role一方放棄了外鍵的維護(hù)權(quán)  -->
        
        <set name="users" table="sys_user_role" inverse="true">
            <key column="role_id"/>
            <many-to-many class="com.itzhouq.hibernate.domain.User" column="user_id"/>
        </set>
    </class>
</hibernate-mapping>

3.1.4 編寫測試類

  • 在主配置文件中引入User.hbm.xmlRole.hbm.xml

    <!-- 配置映射文件 -->
          <mapping resource="com/itzhouq/hibernate/domain/User.hbm.xml"/>
          <mapping resource="com/itzhouq/hibernate/domain/Role.hbm.xml"/>
    
  • 測試類

    package com.itzhouq.hibernate.demo2;
    
    import org.hibernate.Session;
    import org.hibernate.Transaction;
    import org.junit.Test;
    
    import com.itzhouq.hibernate.domain.Role;
    import com.itzhouq.hibernate.domain.User;
    import com.itzhouq.hibernate.utils.HibernateUtils;
    
    /**
     *    Hibernate的多對多的映射
     * @author itzhouq
     *
     */
    public class Demo2 {
      
      @Test
      /*
       *  保存多條記錄:保存多個用戶和角色
       */
      public void test() {
          Session session = HibernateUtils.getCurrentSession();
          Transaction transaction = session.beginTransaction();
          
          // 1. 創(chuàng)建2個用戶
          User user1 = new User();
          user1.setUser_name("趙洪");
          User user2 = new User();
          user2.setUser_name("李兵");
          
          // 2. 創(chuàng)建3個角色
          Role role1 = new Role();
          role1.setRole_name("研發(fā)部");
          Role role2 = new Role();
          role2.setRole_name("市場部");
          Role role3 = new Role();
          role3.setRole_name("公關(guān)部");
          
          // 3. 設(shè)置雙向的關(guān)聯(lián)關(guān)系
          user1.getRoles().add(role1);
          user1.getRoles().add(role2);
          user2.getRoles().add(role2);
          user2.getRoles().add(role3);
          
          role1.getUsers().add(user1);
          role2.getUsers().add(user1);
          role2.getUsers().add(user2);
          role3.getUsers().add(user2);
          
          // 4. 保存操作:多對多建立了雙向的關(guān)系必須有一方放棄外鍵維護(hù)
          // 5. 一般是被動方放棄外鍵維護(hù)     角色是被動方 恨课,需要在Role.hbm.xml文件中配置inverse=true
          //      比如舆乔,學(xué)生選課,課程是被選擇的庄呈,所以課程一方放棄外鍵維護(hù)蜕煌,需要在課程的映射文件中配置inverse=true
          session.save(user1);
          session.save(user2);
          session.save(role1);
          session.save(role2);
          session.save(role3);
          
          transaction.commit();
      }
      
    }
    
  • Role.hbm.xml文件中配置

    <!--inverse="true",Role一方放棄了外鍵的維護(hù)權(quán)  -->
          
          <set name="users" table="sys_user_role" inverse="true">
              <key column="role_id"/>
              <many-to-many class="com.itzhouq.hibernate.domain.User" column="user_id"/>
          </set>
    

3.2 Hibernate的多對多的操作

3.2.1 只保存一邊是否可以

@Test
    /*
     *  多對多的操作
     *  只保存一邊是否可以?不可以诬留,瞬時態(tài)異常
     */
    public void test2() {
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        
        // 1. 創(chuàng)建1個用戶
        User user1 = new User();
        user1.setUser_name("趙洪");
        
        // 2. 創(chuàng)建1個角色
        Role role1 = new Role();
        role1.setRole_name("研發(fā)部");
        
        // 3. 設(shè)置雙向的關(guān)聯(lián)關(guān)系
        user1.getRoles().add(role1);
        role1.getUsers().add(user1);
        
        // 4. 保存用戶
        session.save(user1);
        
        transaction.commit();
    }

3.2.2 級聯(lián)保存或更新

@Test
    /*
     *  多對多的操作
     *  多對多的級聯(lián)保存:
     *  * 保存用戶級聯(lián)保存角色斜纪。主體是用戶。
     *  * 在User.hbm.xml中的set上配置cascade="save-update"
     */
    public void test3() {
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        
        // 1. 創(chuàng)建1個用戶
        User user1 = new User();
        user1.setUser_name("李世民");
        
        // 2. 創(chuàng)建1個角色
        Role role1 = new Role();
        role1.setRole_name("董事局");
        
        // 3. 設(shè)置雙向的關(guān)聯(lián)關(guān)系
        user1.getRoles().add(role1);
        role1.getUsers().add(user1);
        
        // 4. 保存用戶
        session.save(user1);
        
        transaction.commit();
    }

3.2.3 級聯(lián)刪除【基本不用】

  • 級聯(lián)刪除之前先查詢

3.2.4 其他操作

  1. 給用戶選擇角色

    @Test
     /*
      *  給用戶選擇角色
      */
     public void test4() {
         Session session = HibernateUtils.getCurrentSession();
         Transaction transaction = session.beginTransaction();
         // 1. 給1號用戶多選3號角色
         // 2. 查詢1號用戶
         User user = session.get(User.class, 1L);
         // 3. 查詢3號角色
         Role role = session.get(Role.class, 3L);
         // 4. 選擇角色
         user.getRoles().add(role);
         
         transaction.commit();
     }
    
    • 注意修改前需要設(shè)置主配置文件的<property name="hibernate.hbm2ddl.auto">update</property>
  2. 給用戶改選角色

    @Test
     /*
      *  給用戶改選角色
      */
     public void test5() {
         Session session = HibernateUtils.getCurrentSession();
         Transaction transaction = session.beginTransaction();
         // 1. 將2號用戶原有的3號角色改為2號角色
         // 2. 查詢2號用戶
         User user = session.get(User.class, 2L);
         // 3. 查詢3號角色
         Role role3 = session.get(Role.class, 3L);
         // 4. 查詢2號角色
         Role role2 = session.get(Role.class, 2L);
         // 5. 改選角色
         user.getRoles().remove(role3);
         user.getRoles().add(role2);
         
         transaction.commit();
     }
    
  1. 給用戶刪除角色

    @Test
     /*
      *  給用戶刪除角色
      */
     public void test6() {
         Session session = HibernateUtils.getCurrentSession();
         Transaction transaction = session.beginTransaction();
         // 1. 將2號用戶的1號角色刪除
         // 2. 查詢2號用戶
         User user = session.get(User.class, 2L);
         // 3. 查詢1號角色
         Role role = session.get(Role.class, 1L);
         // 4. 刪除角色
         user.getRoles().remove(role);
         transaction.commit();
     }
    
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末文兑,一起剝皮案震驚了整個濱河市盒刚,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌绿贞,老刑警劉巖因块,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異籍铁,居然都是意外死亡涡上,警方通過查閱死者的電腦和手機趾断,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吩愧,“玉大人芋酌,你說我怎么就攤上這事⊙慵眩” “怎么了脐帝?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長糖权。 經(jīng)常有香客問我堵腹,道長,這世上最難降的妖魔是什么星澳? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任疚顷,我火速辦了婚禮,結(jié)果婚禮上募判,老公的妹妹穿的比我還像新娘荡含。我一直安慰自己咒唆,他們只是感情好届垫,可當(dāng)我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著全释,像睡著了一般装处。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上浸船,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天妄迁,我揣著相機與錄音,去河邊找鬼李命。 笑死登淘,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的封字。 我是一名探鬼主播黔州,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼阔籽!你這毒婦竟也來了流妻?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤笆制,失蹤者是張志新(化名)和其女友劉穎绅这,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體在辆,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡证薇,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年度苔,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片浑度。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡林螃,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出俺泣,到底是詐尸還是另有隱情疗认,我是刑警寧澤,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布伏钠,位于F島的核電站横漏,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏熟掂。R本人自食惡果不足惜缎浇,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望赴肚。 院中可真熱鬧素跺,春花似錦、人聲如沸誉券。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽踊跟。三九已至踩验,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間商玫,已是汗流浹背箕憾。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留拳昌,地道東北人袭异。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像炬藤,于是被迫代替她去往敵國和親御铃。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,044評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 本文包括:1刻像、一對多結(jié)構(gòu)的準(zhǔn)備2畅买、雙向關(guān)聯(lián)與單向關(guān)聯(lián)3、級聯(lián)保存4细睡、級聯(lián)刪除5谷羞、cascade 屬性——級聯(lián)6、i...
    廖少少閱讀 1,227評論 1 6
  • 本文包括: 1、CRM 項目的整體介紹 2湃缎、Hibernate 框架概述 3犀填、Hibernate 快速入門 4、H...
    廖少少閱讀 3,475評論 9 66
  • 表與表的關(guān)系 關(guān)鍵是維護(hù)關(guān)聯(lián)屬性 一對多|多對一 一對多(多對一): 數(shù)據(jù)表中: 客戶表 ? 聯(lián)系人表 實體中...
    小閆94閱讀 293評論 0 0
  • layout: posttitle: hibernate--多表subtitle: 多表操作...
    蟲兒飛ZLEI閱讀 99評論 0 0
  • layout: posttitle: hibernatesubtitle: 用法date: ...
    蟲兒飛ZLEI閱讀 329評論 0 1