Hibernate 中一對多和多對多映射


1. 一對多映射

1.1 JavaWeb 一對多建表原則

  • 多方表的外鍵指向一方表的主鍵;

1.2 編寫一對多的 JavaBean

// 客戶(一方)和聯系人(多方)
    // 客戶(一方) JavaBean
    public class Customer{
        private Long cust_id;
        private String cust_name;
        private Long cust_create_id;
        ...

        // 關聯多方
        // Hibernate 框架默認的集合是 Set 集合,該集合必須要自己手動初始化
        private Set<Linkman> linkmans = new HashSet<Linkman>();

        ......
    }

    // 聯系人(多方) JavaBean
    public class Linkman{
        private Long lkm_id;
        private String lkm_name;
        private String lkm_gender;
        ...

        // 關聯一方
        // 編寫一個對象, 不需要自己 new
        private Customer customer;

        ....
    }

1.3 編寫一對多的映射配置文件

// Customer.hbm.xml (客戶映射配置)
    <class name="com.itheima.domain.Customer" table="cst_customer">
        <id name="cust_id" column="cust_id">
            <generator class="native"/>
        </id>

        <property name="cust_name" column="cust_name"/>
        <property name="cust_create_id" column="cust_create_id"/>
        ...

        // 關聯的配置(一方)
        // name  表示集合的名稱
        <set name="linkmans">
            <key column="lkm_cust_id"/>  // column 外鍵的字段
            <one-to-many class="com.itheima.domain.Linkman"/>
        </set>
    </class>


// Linkman.hbm.xml (聯系人映射配置)
    <class name="com.itheima.doamin.Linkman" table="cst_linkman">
        <id name="lkm_id" column="lkm_id">
            <generator class="native"/>
        </id>

        <property name="lkm_name" column="lkm_name"/>
        <property name="lkm_gender" column="lkm_gender"/>
        ...

        // 關聯的配置(多方)
        //  name    當前 JavaBean 中的屬性
        //  class   屬性的全路徑
        //  column  外鍵的字段(表)
        <many-to-one name="customer"  class="com.itheima.domain.Customer" column="lkm_cust_id"/>
    </class>

2. 保存客戶和聯系人的數據

2.1 雙向關聯的方式保存數據

 public class Demo{
    public void fun(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tr = session.beginTransaction();

        // 創建客戶
        Customer c1 = new Customer();
        c1.setCust_name("張三");

        // 創建聯系人
        Linkman lk1 = new Linkman();
        lk1.setLkm_name("熊大");

        Linkman lk2 = new Linkman();
        lk2.setLkm_name("熊二");

        // 雙向關聯
        c1.getLinkmans().add(lk1);
        c1.getLinkmans().add(lk2);

        lk1.setCustomer(c1);
        lk2.setCustomer(c1);

        session.save(c1);
        session.save(lk1);
        session.save(lk2);

        tr.commit();
    }
}

2.2 級聯保存

  • 級聯保存:保存一方,同時可以把關聯的對象也保存到數據庫中!
  • 級聯保存是有方向性的.例如,保存客戶時,級聯保存聯系人;或者,保存聯系人時,級聯保存客戶;
  • 使用 cascade="save-update"
// 保存客戶,級聯保存聯系人
    // 需要在客戶 Customer.hbm.xml 中配置
    <set name="linkmans" cascade="save-update">
        <key column="lkm_cust_id"/>
        <one-to-many class="com.itheima.domain.Linkman"/>
    </set>

    pulic class Demo{

        pulic class fun(){
            Session session = HibernateUtils.getCurrentSession();
            Transaction tr = session.beginTransaction();

            // 創建客戶
            Customer c1 = new Customer();
            c1.setCust_name("張三");

            // 創建聯系人
            Linkman l1 = new Linkman();
            l1.setLkm_name("熊大");

            Linkman l2 = new Linkman();
            l2.setLkm_name("熊二");

            // 單向關聯
            c1.getLinkmans().add(l1);
            c1.getLinkmans().add(l2);

            l1.setCustomer(c1); // 此處,如果沒有,報錯.
            l2.setCustomer(c1); // 此處,如果沒有,報錯.

            // 保存客戶
            session.save(c1);

            tr.commit();
        }
    }


// 保存聯系人,級聯保存客戶
    // 需要在聯系人 Linkman.hbm.xml 中配置
    <many-to-one name="customer" class="cn.itheima.domain.Customer"
                    column="lkm_cust_id" cascade="save-update"/>

    public class Demo{
        public class fun(){
            Session session = HibernateUtils.getCurrentSession();
            Transaction tr = session.beginTransaction();

            // 創建客戶
            Customer c1 = new Customer();
            c1.setCust_name("張三");

            // 創建聯系人
            Linkman l1 = new Linkman();
            l1.setLkm_name("熊大");

            Linkman l2 = new Linkman();
            l2.setLkm_name("熊二");

            l1.setCustomer(c1);
            l2.setCustomer(c2);

            // 保存聯系人
            session.save(l1);
            session.save(l2);

            tr.commit();
        }
    }

2.3 級聯刪除

  • 級聯刪除也是有方向性的;
// 刪除客戶時, 刪除聯系人(一方級聯刪除多方), 配置 Customer.hbm.xml
    <set name="linkmans" cascade="delete">
        <key column="lkm_cust_id"/>
        <one-to-many class="cn.itheima.domain.Linkman"/>
    </set>

2.4 級聯的取值和孤兒刪除

1. 級聯的取值(cascade 的取值)
  • none: 不使用級聯;
  • save-update: 級聯保存或更新;
  • delete: 級聯刪除;
  • delete-orphan: 孤兒刪除(只能應用在一對多關系);
  • all: 除了 delete-orphan 的所有情況;
  • all-delete-orphan: 包含了 delete-orphan 的所有情況;
2. 孤兒刪除
  • 只有在一對多的環境下才有孤兒刪除;
  • 在一對多的關系中,可以將一方認為是父方,將多的一方認為是子方;孤兒刪除,就是在解除了父子關系的時候,
    將子方記錄直接刪除;

2.5 讓某一方放棄外鍵的維護,為多對多映射做准備: inverse

  1. 在修改客戶和聯系人的關系時,進行雙向關聯,雙方都會維護外鍵,會產生多余的 SQL 語句.
    • 產生的原因: session 的一級緩存中的快照機制,會讓雙方都更新數據庫,產生了多余的 SQL 語句.
  2. 如果不想產生多余的 SQL 語句,那么需要一方來放棄外鍵的維護, 由多方來維護!
// 放棄外鍵維護
    // Customer.hbm.xml 進行如下配置
    <set name="linkman" inverse="true">  // true 表示放棄; 默認值為 false
        <key column="lkm_cust_id"/>
        <one-to-many class="com.itheima.domain.Linkman"/>
    </set>

3. 多對多映射

3.1 多對多建表原則

  • 以用戶和角色為例,需要創建三張表: 用戶表,角色表,中間表(維護前面兩個表的數據);
  • 使用Hibernate 框架,只要編寫兩個 JavaBean 以及對應的映射配置文件,中間表會自動生成;
  • 多對多映射關系中,必須有一方放棄外鍵維護;

// 編寫用戶和角色的 JavaBean
    // 用戶的 JavaBean
    public class User{
        private Long user_id;
        private String user_name;
        private String user_pwd;
        ...

        private Set<Role> roles = new HashSet<Role>();
    }

    // 角色的 JavaBean
    public class Role{
        private Long role_id;
        private String role_name;
        private String role_desc;

        private Set<User> users = new HashSet<User>();
    }


// 編寫映射配置文件
    // 用戶的映射配置文件, User.hbm.xml
    <class name="com.itheima.domain.User" table="sys_user">
        <id name="user_id" column="user_id">
            <generator class="native"/>
        </id>

        <property name="user_name" column="user_name"/>
        <property name="user_pwd" column="user_pwd"/>

        // 配置多對多
        // name 表示集合的名稱
        // table 表示中間表的名稱
        <set name="roles" table="sys_user_role" inverse="true">
            // 當前對象在中間表的外鍵名稱
            <key column="user_id"/>

            // class : 集合中存入的對象,對象的全路徑
            // column: 集合中對象,在中間表的外鍵名稱
            <many-to-many class="com.itheima.domain.Role" column="role_id"/>
        </set>

    </class>

    // 角色的映射配置文件, Role.hbm.xml
    <class name="com.itheima.domain.Role" table="sys_role">
        <id name="role_id" column="role_id">
            <generator class="native"/>
        </id>

        <property name="role_name" column="role_name"/>
        <property name="role_desc" column="role_desc"/>

        <set name="users" table="sys_user_role">
            <key column="role_id"/>
            <many-to-many class="com.itheima.domain.User" column="user_id"/>
        </set>
    </class>    

參考資料


免責聲明!

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



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