1. 程式人生 > >Hibernate入門(二)

Hibernate入門(二)

方式 分享 數據庫表 left use acl att commit cti

一、主鍵生成策略

1.主鍵的類型

  • 自然主鍵: 把有特定業務含義的字段作為了主鍵 eg: 用戶的名字, 身份證號碼

  • 代理主鍵: 把沒有特定業務含義的字段作為了主鍵 eg: id

 開發裏面的話通常用代理主鍵

2.主鍵的生成策略

2.1概述

? Hibernate中為了更好的維護數據, 提供很多種主鍵生成策略.

2.2 主鍵策略類型
  • increment :自動增長,適用類型:short,int,long類型主鍵.在多進程和集群下不要使用.用的不是數據庫的自動增長, hibernate底層的增長策略,select max(id) from customer; 然後+1作為下一條記錄的ID.

  • assigned:需要用戶手動輸入OID的.

  • identity:自動增長,用的是數據庫的自動增長。適用類型:short,int,long類型主鍵.支持自動增長數據庫如Mysql

  • sequence:序列,適用類型:short,int,long類型主鍵.支持序列的數據庫如:Oracle.

  • native:本地策略,根據數據庫的底層采用使用identity還是sequence.

  • uuid:隨機的字符串,適用於字符串類型的主鍵.

  規則: 如果主鍵類型是 int short long 用 native

?      如果主鍵類型是字符串, 用uuid

二、持久化類的編寫規則

1.持久化類概述

?   在Hibernate中,用來描述數據庫表結構的類,稱之為持久化類.

?   Java類與數據庫的某個表建立了映射關系.這個類就稱為是持久化類

?   持久化類 = Java類 + hbm的配置文件

2.持久化類定義規範

  • 遵循JavaBean定義規範

    ? 類是公有的

    ? 需要一個無參的構造函數

    ? 屬性是私有的,需要提供公共的getter和setter方法進行訪問屬性

  • 必須用一個屬性描述數據庫表的主鍵

  • 主鍵屬性的類型必須是引用類型,且需要實現Serializable接口

三、 持久化對象的三種狀態

1.概述

?   由持久化類創建的對象就是持久化對象。Hibernate為了管理持久化對象:將持久化對象分成了三個狀態.hibernate底層實現過程中,定義的三種狀態主要方便開發人員調用session的API.

?   區分三種狀態:

?     瞬時態 :沒有持久化標識OID的,沒有納入到session的管理.

?     持久態 :有持久化標識OID的,已經納入到session的管理.

?     托管(遊離態)態:有持久化標識OID的,沒有納入到session的管理.

java代碼:

/**
 * 區分三種狀態:
 * 瞬時態: 沒有持久化標識oid,沒有納入Session管理
 * 持久態: 有持久化標識oid,並且納入了Session管理
 * 托管態: 有持久化標識oid,但沒有納入Session管理
 */    
    @Test
    public void fun01(){
        Session session = HibernateUtils.openSession();
        Transaction transaction = session.beginTransaction();
        transaction.begin();
        
        User user = new User();//瞬時態
        user.setUname("張三");
        user.setUage(18);
        
        session.save(user);
        System.out.println(user.toString());//持久態
        
        transaction.commit();
        session.close();
        System.out.println(user.toString());//托管態
    }

2.三種狀態的轉換

技術分享圖片

2.1瞬時態對象

沒有持久化標識OID, 沒有被納入到Session對象的管理

  • 獲得:new對象

  • 狀態轉換:

    ? 瞬時態--->持久態:save()/saveOrUpdate();

    ? 瞬時態--->托管態:把瞬時態對象設置一個id

2.2持久態對象

有持久化標識OID,已經被納入到Session對象的管理

  • 獲得:get()/load()/find()..

  • 狀態轉換:

    ? 持久態--->瞬時態:session.delete(); (Hibernate中不建議使用的)

    ? 持久態--->托管態:close()/clear()/evict(Object obj);

2.3托管態對象

  有持久化標識OID,沒有被納入到Session對象的管理

  • 獲得:new對象,給對象設置id

  • 狀態轉換:

    ? 托管態-->瞬時態:把對象的id設置為null

    ? 托管態--->持久態:update()/saveOrUpdate();

3.持久態對象可以自動更新數據庫

  持久態對象依賴於緩存可以自動更新數據庫

  • Java代碼

 1     @Test
 2     public void fun05(){
 3         Session session = HibernateUtils.openSession();
 4         Transaction transaction = session.beginTransaction();
 5         transaction.begin();
 6         //持久態對象
 7         User user = session.get(User.class, 1);
 8         user.setUname("李四");
 9         //session.update(user);可以不寫,因為當前的user是持久化對象
10 
11         transaction.commit();
12         session.close();
13     }

四、hibernate的緩存

1.緩存概述

?   緩存就是一塊內存空間。

?   將數據源(數據庫或者文件)中的數據讀取出來存放到緩存中,再次獲取的時候 ,直接從緩存中獲取,這樣可以提升程序的性能!

?   作用:提升程序的性能

2.Hibernate的緩存類別

?   一級緩存:session對象的緩存,自帶的不可卸載的. 一級緩存的生命周期與session一致。

?   二級緩存:二級緩存可以在多個session中共享數據。一般不會用,企業裏通常使用Redis

3.一級緩存

?   在 Session 接口的實現中包含一系列的 Java集合,這些 Java 集合構成了 Session 緩存. 只要 Session 實例沒有結束生命周期, 存放在它緩存中的對象也不會結束生命周期.

?   當session的save()方法持久化一個對象時,該對象被載入緩存,以後即使程序中不再引用該對象,只要緩存不清空,該對象仍然處於生命周期中。當試圖get()、 load()對象時,會判斷緩存中是否存在該對象,有則返回,此時不查詢數據庫。沒有再查詢數據庫.

    @org.junit.Test
    public void fun03(){
        Session session = HibernateUtils.openSession();
        Transaction transaction = session.beginTransaction();

        //持久態對象
        User user1 = session.get(User.class, 1);//馬上發送一條sql語句
        System.out.println(user1.toString());

        User user2 = session.get(User.class, 1);//馬上發送一條sql語句
        System.out.println(user1 == user2);//true

        transaction.commit();
        session.close();
    }

測試結果:

Hibernate:
  select
    user0_.uid as uid1_0_0_,
    user0_.uname as uname2_0_0_,
    user0_.uage as uage3_0_0_
  from
    user user0_
  where
    user0_.uid=?
User{uid=1, uname=‘李四‘, uage=18}
true

4.一級緩存的內部結構:(緩存區, 快照區)

技術分享圖片

五、Hibernate的事務

1.事務的概念

?   事務就是邏輯上的一組操作,組成事務的各個執行單元,操作要麽全都成功,要麽全都失敗.

2.事務的特性

?   原子性: 事務不可分割.

?     eg: 張三 1000 李四 1000; 張三給李四轉100, 要麽轉賬成功,要麽失敗

?   一致性: 事務執行的前後數據的完整性保持一致.

?     eg: 張三 1000 李四 1000 =2000; 張三給李四轉100, 成功了 張三 900 李四1100 = 2000; 失敗

  ? 隔離性: 一個事務執行的過程中,不應該受到其他的事務的幹擾.

?   持久性: 事務一旦提交,數據就永久保持到數據庫中.

?     eg: 張三 1000 李四 1000, 給李四轉520;

3.不考慮隔離性會出現的相關問題

  • 臟讀: 一個事務讀到了另一個事務未提交的數據.

  • 不可重復讀: 一個事務讀到了另一個事務已經提交的update數據,導致多次查詢結果不一致. 張三 1000 ; 李四 1000

  • 虛讀: 一個事務讀到了另一個事務已經提交的insert數據,導致多次查詢結構不一致.

4.隔離級別

隔離級別含義
READ_UNCOMMITTED 允許你讀取還未提交的改變了的數據。可能導致臟、幻、不可重復讀
READ_COMMITTED 允許在並發事務已經提交後讀取。可防止臟讀,但幻讀和 不可重復讀仍可發生
REPEATABLE_READ 對相同字段的多次讀取是一致的,除非數據被事務本身改變。可防止臟、不可重復讀,但幻讀仍可能發生。
SERIALIZABLE 完全服從ACID的隔離級別,確保不發生臟、幻、不可重復讀。這在所有的隔離級別中是最慢的,它是典型的通過完全鎖定在事務中涉及的數據表來完成的。

實際開發中,不會選擇最高或者最低隔離級別,選擇 READ_COMMITTED(oracle 默認)、REPEATABLE_READ (mysql默認)

5.Hibernate配置隔離級別

  hibernate通過在hibernate.cfg.xml的配置文件中設置隔離級別:

<property name="hibernate.connection.isolation">4</property>

  取值

    ? 1: Read uncommitted isolation,讀未提交

?     2: Read committed isolation,讀已提交,解決臟讀。

?     4: Repeatable read isolation,可重復讀

?     8: Serializable isolation,串行化

6.hibernate對 session的管理

6.1把Session綁定在當前線程

?   在開發中,通常在業務層進行事物管理,在Dao層操作數據庫. 也就是說業務層需要連接(Session)開啟事物,Dao層需要連接(Session)操作數據庫,如何保證這些連接是同一個呢?

? 在JDBC階段,我們通過了兩種方式解決:

  ? 1.向下傳遞參數

?   2.綁定到TreadLocal裏面.

?   在Hibernate中,Session 對象與本地線程綁定很簡單,只需要兩步:

  • 在hibernate.cfg.xml文件中,添加屬性,開啟與本地線程綁定的session

    <property name="hibernate.current_session_context_class">thread</property>
  • 通過SessionFactory的getCurrentSession()方法獲得Session

    Session session = sessionFactory.getCurrentSession();

    註意:通過getCurrentSession()方法獲得的session,無需調用close方法釋放資源。當事物提交或者回滾,會自動釋放資源.

6.2 Session獲取方式的區別
  • 調用getCurrentSession()方法時,會判斷當前線程中是否綁定了session。

    ? 如果綁定了,直接返回線程中綁定的session

    ? 如果沒有綁定,先去創建一個session,然後講session存儲到當前線程中,再返回。

  • 調用openSession()方法時,只會創建一個新的session,且不會存儲到當前線程。

  • 通過getCurrentSession()方法獲得的session,無需調用close方法釋放資源. 通過openSession()方法獲得的session需要手動釋放資源。

Hibernate入門(二)