Hibernate第三天

回顧Hibernate第二天:

1.  一對多與多對一

2. 多對多

3. inverse/cascade

4. 關聯關係的維護

 

 

一對多:

         <set name="映射的集合屬性" table="(可選)集合屬性對應的外鍵表">

            <key column="外鍵表的,外鍵字段" />

            <one-to-many class="集合元素的類型" />

         </set>

 

多對一:

    <many-to-one name="對象屬性" class="對象類型" column="外鍵字段字段" />

 

多對多

    <set name="" table="">

        <key column="" />

        <many-to-many column="" class="">

    </set>

 

目標:

         1部分: 對象的狀態:

         第2部分:緩存

                   1)一級緩存

                   2)相關知識

         ----懶加載---

         第3部分:映射

                  一對一映射

                   組件映射

                   繼承映射

                  

一、對象的狀態

舉例: User   user   = new User();

 

Hibernate中對象的狀態: 臨時/瞬時狀態、持久化狀態、遊離狀態。

ü  臨時狀態[A1] 

特點:

直接new出來的對象; 

不處於session的管理;

數據庫中沒有對象的記錄;

ü  持久化狀態

當調用sessionsave/saveOrUpdate/get/load/list等方法的時候,對象就是持久化狀態。

處於持久化狀態的對象,當對對象屬性進行更改的時候,會反映到數據庫中!

特點:

處於session的管理;

數據庫中有對應的記錄;

ü  遊離狀態

特點

             不處於session的管理;

                   數據庫中有對應的記錄

                   Session關閉後,對象的狀態;

 

對象狀態的轉換,

 

 

 

二、一級緩存

爲什麼要用緩存?

         目的:減少對數據庫的訪問次數!從而提升hibernate的執行效率!

Hibernate中緩存分類:

         一級緩存

         二級緩存

 

ü  概念

1)Hibenate中一級緩存,也叫做session的緩存,它可以在session範圍內減少數據庫的訪問次數!  只在session範圍有效! Session關閉,一級緩存失效!

2)當調用session的save/saveOrUpdate/get/load/list/iterator方法的時候,都會把對象放入session的緩存中。

3)Session的緩存由hibernate維護,用戶不能操作緩存內容; 如果想操作緩存內容,必須通過hibernate提供的evit/clear方法操作。

特點:

         只在(當前)session範圍有效,作用時間短,效果不是特別明顯!

         在短時間內多次操作數據庫,效果比較明顯!

 

 

ü  緩存相關幾個方法的作用

session.flush();       讓一級緩存與數據庫同步

                   session.evict(arg0);    清空一級緩存中指定的對象

                   session.clear();       清空一級緩存中緩存的所有對象

 

在什麼情況用上面方法?

          批量操作使用使用:

                    Session.flush();   // 先與數據庫同步

                    Session.clear();   // 再清空一級緩存內容

                  

 

 

ü  面試題1: 不同的session是否會共享緩存數據?

不會。

User1  u1 = Session1.get(User.class,1);   把u1對象放入session1的緩存

Session2.update(u1);     把u1放入session2的緩存

 

U1.setName(‘newName’);

 

如果生成2條update sql, 說明不同的session使用不同的緩存區,不能共享。

 

ü  面試題2: list與iterator查詢的區別?

list()

一次把所有的記錄都查詢出來,

會放入緩存,但不會從緩存中獲取數據

         Iterator

                   N+1查詢; N表示所有的記錄總數

                   即會先發送一條語句查詢所有記錄的主鍵(1),

再根據每一個主鍵再去數據庫查詢(N)!

會放入緩存,也會從緩存中取數據!

 

 

三、懶加載

ü  面試題3: get、load方法區別?

get: 及時加載,只要調用get方法立刻向數據庫查詢

load:默認使用懶加載,當用到數據的時候才向數據庫查詢。

 

ü  懶加載:(lazy)

概念:當用到數據的時候才向數據庫查詢,這就是hibernate的懶加載特性。

                   目的:提供程序執行效率!

ü  lazy 值

         true   使用懶加載

         false   關閉懶加載

         extra   (在集合數據懶加載時候提升效率)

在真正使用數據的時候才向數據庫發送查詢的sql;

如果調用集合的size()/isEmpty()方法,只是統計,不真正查詢數據!

                           

 

ü  懶加載異常

n  Session關閉後,不能使用懶加載數據!

n  如果session關閉後,使用懶加載數據報錯:

org.hibernate.LazyInitializationException: could not initializeproxy - no Session

                   如何解決session關閉後不能使用懶加載數據的問題?

                            // 方式1先使用一下數據

                   //dept.getDeptName();

                  // 方式2:強迫代理對象初始化

                   Hibernate.initialize(dept);

                  // 方式3:關閉懶加載

                            設置lazy=false;

                   // 方式4在使用數據之後,再關閉session

                           

        

 

四、一對一映射

需求: 用戶身份證信息

          一條用戶記錄對應一條身份證信息!  一對一的關係!

設計數據庫:

JavaBean:

映射:

 

基於外鍵的映射

// 身份證

public class IdCard {

 

    // 身份證號(主鍵)

    private String cardNum;// 對象唯一表示(Object Identified, OID)

    private String place; //  身份證地址

    // 身份證與用戶,一對一的關係

    private User user;

   

// 用戶

public class User {

 

    private int userId;

    private String userName;

    // 用戶與身份證信息,一對一關係

    private IdCard idCard;

   

 

<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC

    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

 

<hibernate-mapping package="cn.itcast.c_one2one">

   

    <class name="IdCard" table="t_IdCard">

        <id name="cardNum">

            <generator class="assigned"></generator>

        </id>  

        <property name="place" length="20"></property>

       

        <!--

            一對一映射,有外鍵方

            unique="true"   給外鍵字段添加唯一約束

         -->

         <many-to-one name="user" unique="true" column="user_id" class="User" cascade="save-update"></many-to-one>

           

    </class>

   

 

</hibernate-mapping>

 

 

<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC

    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

 

<hibernate-mapping package="cn.itcast.c_one2one">

   

    <class name="User" table="t_user">

        <id name="userId">

            <generator class="native"></generator>

        </id>  

        <property name="userName" length="20"></property>

        <!--

            一對一映射:沒有外鍵方

         -->

         <one-to-one name="idCard" class="IdCard"></one-to-one>

             

    </class>

   

 

</hibernate-mapping>

 

 

基於主鍵的映射

// 身份證

public class IdCard {

 

    private int user_id;

    // 身份證號

    private String cardNum;

    private String place; //  身份證地址

    // 身份證與用戶,一對一的關係

    private User user;

   

   

 

<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC

    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

 

<hibernate-mapping package="cn.itcast.c_one2one2">

   

    <class name="IdCard" table="t_IdCard">

        <id name="user_id">

            <!--

                id 節點指定的是主鍵映射, user_id是主鍵

                主鍵生成方式: foreign  即把別的表的主鍵作爲當前表的主鍵;

                        property (關鍵字不能修改)指定引用的對象     對象的全名 cn..User  對象映射 cn.User.hbm.xml   table(id)

             -->

            <generator class="foreign">

                <param name="property">user</param>

            </generator>

        </id>  

        <property name="cardNum" length="20"></property>

        <property name="place" length="20"></property>

       

        <!--

            一對一映射,有外鍵方

            (基於主鍵的映射)

             constrained="true"  指定在主鍵上添加外鍵約束

         -->

        <one-to-one name="user" class="User" constrained="true"  cascade="save-update"></one-to-one>

           

    </class>

   

 

</hibernate-mapping>

 

 

 

 

 

五、組件映射與繼承映射

類的關係

         組合關係

                   一個類中包含了另外一個類。這2個類中就是組合關係。

                   需求: 汽車與車輪

         繼承關係

                   一個類繼承另外一個類。這2個類中就是繼承關係。

                   需求:動物

猴子

組件映射

類組合關係的映射,也叫做組件映射!

注意:組件類和被包含的組件類,共同映射到一張表!

需求:汽車與車輪

數據庫

         T_car

                   主鍵   汽車名稱  輪子大小  個數

Javabean:

 

public class Car {

 

    private int id;

    private String name;

    // 車輪

    private Wheel wheel;

}

// 車輪

public class Wheel {

 

    private int count;

    private int size;

}

<hibernate-mapping package="cn.itcast.d_component">

   

    <class name="Car" table="t_car">

        <id name="id">

            <generator class="native"></generator>

        </id>  

        <property name="name" length="20"></property>

       

        <!-- 組件映射 -->

        <component name="wheel">

            <property name="size"></property>

            <property name="count"></property>

        </component>

       

                     

    </class>

   

 

</hibernate-mapping>

 

 

 

繼承映射

需求:動物

猴子

 

簡單繼承映射

// 動物類

public abstract class Animal {

 

    private int id;

    private String name;

   

<!--

    簡單繼承

 -->

<hibernate-mapping package="cn.itcast.e_extends1">

   

    <class name="Cat" table="t_Cat">

        <!-- 簡單繼承映射:父類屬性直接寫 -->

        <id name="id">

            <generator class="native"></generator>

        </id>

        <property name="na"></property>

        <property name="catchMouse"></property>                   

    </class>

   

 

</hibernate-mapping>

 

@Test

    public void getSave() {

       

        Session session = sf.openSession();

        session.beginTransaction();

       

        // 保存

//      Cat cat = new Cat();

//      cat.setName("大花貓");

//      cat.setCatchMouse("抓小老鼠");

//      session.save(cat);

       

        // 獲取時候注意:當寫hql查詢的使用,通過父類查詢必須寫上類的全名

        Query q = session.createQuery("from cn.itcast.e_extends1.Animal");

        List<Animal> list = q.list();

        System.out.println(list);

       

        session.getTransaction().commit();

        session.close();

       

    }

   

 

 

總結:

         簡單繼承映射,有多少個子類,寫多少個映射文件!

繼承映射

需求:貓、猴子、動物。

所有子類映射到一張表 (1張表)

什麼情況用?

         子類教多,且子類較爲簡單,即只有個別屬性!

         好處:因爲使用一個映射文件, 減少了映射文件的個數。

         缺點:(不符合數據庫設計原則)

一個映射文件: Animal.hbm.xml

                            (如何區分是哪個子類的信息?)

 

 

數據庫:

         T_animal(要存儲所有的子類信息)                 “鑑別器”

                   Id   name     catchMouse      eatBanana              type_(區別是哪個子類)

        1   大馬猴       NULL        吃10個香蕉     猴子

                    2   大花貓     不抓老鼠         NULL          貓

 

 

總結:

         寫法較爲簡單:所有子類用一個映射文件,且映射到一張表!

         但數據庫設計不合理!

         (不推薦用。)

每個類映射一張表(3張表)

數據庫

  T_anmal(存儲父類信息)

         1   大花貓

  T_cat(引用父類的主鍵)

    1  抓小老鼠

T_monkey(引用父類的主鍵)

 

Javabean設計一樣,映射實現不同:

 

<!--

    繼承映射,每個類對應一張表(父類也對應表)

 -->

<hibernate-mapping package="cn.itcast.e_extends3">

   

    <class name="Animal" table="t_animal">

        <id name="id">

            <generator class="native"></generator>

        </id>

        <property name="name"></property>

       

        <!--

            子類:貓  t_cat

            key 指定_cat表的外鍵字段

        -->

        <joined-subclass name="Cat" table="t_cat">

            <key column="t_animal_id"></key>

            <property name="catchMouse"></property>

        </joined-subclass>

       

        <!-- 子類:猴子  t_monkey -->

        <joined-subclass name="Monkey" table="t_monkey">

            <key column="t_animal_id"></key>

            <property name="eatBanana"></property>

        </joined-subclass>

       

    </class>

   

 

</hibernate-mapping>

 

 

 

總結:

       一個映射文件,存儲所有的子類; 子類父類都對應表;

   缺點:表結構比較負責,插入一條子類信息,需要用2條sql:往父類插入、往子類插入!

(推薦)每個子類映射一張表,父類不對應表(2張表)

數據庫:

         T_cat

                   Id   name  catchMounse

         T_monkey

                   Id    name  eatBanana

 

<union-subclass name="Cat" table="t_cat">

        <property name="catchMouse"></property>

      </union-subclass>

注意:主鍵不能是自增長!

 

總結:

         所有的子類都寫到一個映射文件;

父類不對應表; 每個子類對應一張表

 

 

Hibernate中映射:

         多對一

         一對多

         多對多

         一對一  (多對一的特殊應用)

         組件

         繼承


 [A1]3種狀態

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章