1. 程式人生 > >Hibernate 學習筆記 之 一對多關係 及其 級聯操作

Hibernate 學習筆記 之 一對多關係 及其 級聯操作

一、一對多關係

這裡寫圖片描述

Customer.java


/**
 * Created by Donald on 2016/11/19.
 */
public class Customer {
    private Integer cid;
    private String custName;
    private String custLevel;
    private String custSource;  //客戶來源
    private String custPhone;   //聯絡電話
    private String custMobile;  //手機

    /**
     * 在客戶實體類裡面表示多個聯絡人,一個客戶有多個聯絡人
     * hibernate要求使用集合表示多的資料,使用set集合
     * */
private Set<LinkMan> setLinkMan = new HashSet<LinkMan>(); public Set<LinkMan> getSetLinkMan() { return setLinkMan; } public void setSetLinkMan(Set<LinkMan> setLinkMan) { this.setLinkMan = setLinkMan; } public Integer getCid() { return
cid; } public void setCid(Integer cid) { this.cid = cid; } public String getCustName() { return custName; } public void setCustName(String custName) { this.custName = custName; } public String getCustLevel() { return custLevel; } public
void setCustLevel(String custLevel) { this.custLevel = custLevel; } public String getCustSource() { return custSource; } public void setCustSource(String custSource) { this.custSource = custSource; } public String getCustPhone() { return custPhone; } public void setCustPhone(String custPhone) { this.custPhone = custPhone; } public String getCustMobile() { return custMobile; } public void setCustMobile(String custMobile) { this.custMobile = custMobile; } }

Customer.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <!-- 1.配置類和表對應
        class標籤
        name屬性,實體類
        table屬性,資料表名稱
        -->
    <class name="com.yyf.entity.Customer" table="t_customer">
        <id name="cid" column="cid">
            <generator class="native"></generator>
        </id>
        <property name="custName" column="custName" ></property>
        <property name="custLevel" column="custLevel"></property>
        <property name="custSource" column="custSource"></property>
        <property name="custPhone" column="custPhone"></property>
        <property name="custMobile" column="custMobile"></property>

        <!-- 在客戶對映檔案中,表示所有聯絡人
            使用set標籤表示所有聯絡人
            set標籤裡面有name屬性,屬性值寫在客戶實體類裡面表示聯絡人的set結合名稱
        -->
        <set name="setLinkMan" cascade="save-update,delete">
            <!--
                一對多建表,有外來鍵
                hibernate機制,雙向維護外來鍵,在一和多那一方都配置外來鍵
                column屬性值就是外來鍵名稱
            -->
            <key column="clid"></key>
            <!-- 客戶所有的聯絡人,class裡面寫聯絡人實體類全路徑 -->
            <one-to-many  class="com.yyf.entity.LinkMan" />
        </set>
    </class>
</hibernate-mapping>

LinkMan.java

/**
 * Created by Donald on 2016/11/19.
 */
public class LinkMan {
    private Integer lkm_id;     //聯絡人編號(主鍵)
    private String lkm_name;    //聯絡人姓名
    private String lkm_gander;  //聯絡人性別
    private String lkm_phone;   //聯絡人辦公電話

    /**
     * 在聯絡人實體類裡面表示所屬客戶,
     * 一個聯絡人只能屬於一個客戶
     */
    private Customer customer;

    public Customer getCustomer() {
        return customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }

    public Integer getLkm_id() {
        return lkm_id;
    }

    public void setLkm_id(Integer lkm_id) {
        this.lkm_id = lkm_id;
    }

    public String getLkm_name() {
        return lkm_name;
    }

    public void setLkm_name(String lkm_name) {
        this.lkm_name = lkm_name;
    }

    public String getLkm_gander() {
        return lkm_gander;
    }

    public void setLkm_gander(String lkm_gander) {
        this.lkm_gander = lkm_gander;
    }

    public String getLkm_phone() {
        return lkm_phone;
    }

    public void setLkm_phone(String lkm_phone) {
        this.lkm_phone = lkm_phone;
    }
}

LinkMan.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <!-- 1.配置類和表對應
        class標籤
        name屬性,實體類
        table屬性,資料表名稱
        -->
    <class name="com.yyf.entity.LinkMan" table="t_linkman">
        <id name="lkm_id" column="lkm_id">
            <generator class="native"></generator>
        </id>
        <property name="lkm_name" column="lkm_name"></property>
        <property name="lkm_gander" column="lkm_gander"></property>
        <property name="lkm_phone" column="lkm_phone"></property>


        <!-- 表示聯絡人所屬客戶
            name屬性,因為在聯絡人實體類使用customer物件表示,寫customer名稱
            class屬性: customer全路徑
            column屬性:外來鍵名稱
        -->
        <many-to-one name="customer" class="com.yyf.entity.Customer" column="clid" ></many-to-one>
    </class>
</hibernate-mapping>

hibernate.cfg.xml

<?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>
        <!-- 第一部分, 配置資料庫資訊 -->
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql://127.0.0.1:3306/hibernate</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password">admin</property>

        <!--第二部分 配置hibernate資訊-->
        <!-- 輸出底層sql語句-->
        <property name="hibernate.show_sql">true</property>
        <!-- 輸出底層sql語句格式-->
        <property name="hibernate.format_sql">true</property>
        <!-- hibernate幫建立表,需要配置之後
            update: 如果已經有這個表,則更新,如果沒有,建立
        -->
        <property name="hibernate.hbm2ddl.auto">update</property>
        <!-- 配置資料庫方言
            在mysql裡面實現分頁 關鍵字 limit,只能使用在mysql裡
            在oracle資料庫,實現分頁rownum
            讓hiberna框架識別不同資料庫的語句
        -->
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

        <!-- 在hibernate核心配置檔案中配置-->
        <property name="hibernate.current_session_context_class">thread</property>

        <!--第三部分 把對映檔案放到核心配置檔案中-->
        <mapping resource="com/yyf/entity/Customer.hbm.xml" />
        <mapping resource="com/yyf/entity/LinkMan.hbm.xml" />
    </session-factory>
</hibernate-configuration>

首先

為方便操作,減少程式碼量,可以在一對多中的“一”的Xxx.hbm.xml裡進行配置,如下圖:

這裡寫圖片描述

二、級聯操作 — 更新

 /**
     * 簡化寫法
     * 一般根據客戶新增聯絡人
     * (1)在客戶對映檔案中進行配置
     * 在客戶對映檔案裡面set標籤進行配置
     *
     * (2)建立客戶和聯絡人物件,
     * 只需要把聯絡人放在客戶裡面就可以了,
     * 最終只需要儲存客戶就可以了。
     */

    @Test
    public void testAdd2() {
        SessionFactory sessionFactory = null;
        Session session = null;
        Transaction tx = null;
        try{
            sessionFactory = HibernateUtils.getSessionFactory();
            session = sessionFactory.openSession();
            tx = session.beginTransaction();

            //1.建立客戶和聯絡人物件
            Customer customer = new Customer();
            customer.setCustName("百度");
            customer.setCustLevel("普通客戶");
            customer.setCustSource("網路");
            customer.setCustPhone("110");
            customer.setCustMobile("999");

            LinkMan linkMan = new LinkMan();
            linkMan.setLkm_name("小紅");
            linkMan.setLkm_gander("男");
            linkMan.setLkm_phone("911");

            //2.把聯絡人放在客戶裡面
            customer.getSetLinkMan().add(linkMan);

            //3.儲存客戶
            session.save(customer);


            tx.commit();
        }catch (Exception e){
            tx.rollback();
        }
    }

三、級聯操作 — 刪除

/**
     * 1. 刪除某個客戶,把客戶裡面所有的聯絡人刪除
     *
     * (1)使用屬性cascade屬性值delete
     *
     * (2)在程式碼中直接刪除客戶
     *      根據id查詢物件,呼叫session裡面delete方法刪除
     */
    @Test
    public void testDelete() {
        SessionFactory sessionFactory = null;
        Session session = null;
        Transaction tx = null;
        try{
            sessionFactory = HibernateUtils.getSessionFactory();
            session = sessionFactory.openSession();
            tx = session.beginTransaction();

            //1.根據id查詢客戶物件
            Customer customer = session.get(Customer.class, 2);
            //2.呼叫方法刪除
            session.delete(customer);


            tx.commit();
        }catch (Exception e){
            tx.rollback();
        }
    }

四、操作 — inverse

這裡寫圖片描述

若不加這個屬性則在更新外來鍵時候,則會雙向維護,即更新兩次,造成不必要的浪費

/**
     * inverse屬性
     *
     * (1)因為hibernate雙向維護外來鍵,在客戶和聯絡人裡面都需要
     * 維護外來鍵,修改客戶時候修改一次外來鍵,修改聯絡人時候也修改一次外來鍵,造成效率問題
     *
     * (2)解決方式:讓其中的一方不維護外來鍵
     * - 一對多裡面,讓其中一方放棄外來鍵維護
     * - 一個國家有總統。國家有很多人,總統不能認識國家所有人,國家所有人可以認識總統
     *
     * (3)具體實現:
     * 在放棄關係維護對映檔案中,進行配置,在set標籤上使用inverse
     */
    @Test
    public void testUpdate() {
        SessionFactory sessionFactory = null;
        Session session = null;
        Transaction tx = null;
        try{
            sessionFactory = HibernateUtils.getSessionFactory();
            session = sessionFactory.openSession();
            tx = session.beginTransaction();

            //1.根據id查詢客戶物件
            Customer customer = session.get(Customer.class, 2);
            LinkMan linkMan = session.get(LinkMan.class, 1);

            customer.getSetLinkMan().add(linkMan);
            linkMan.setCustomer(customer);

            tx.commit();
        }catch (Exception e){
            tx.rollback();
        }
    }