Hibernate 生成策略和緩存策略

主鍵生成策略

1、主鍵分類

1. 天然主鍵

主鍵自己就是表中的一個字段,實體中一個具體的屬性,對象自己惟一的特性redis

好比:建立一個學生表:姓名、年齡、身份證號(天然主鍵)sql

2. 代理主鍵

主鍵自己不是表中必須的一個字段數據庫

一樣建立一個學生表:姓名、年齡 、身份證號、SID(代理主鍵)緩存

在實際開發當中儘可能要使用代理主鍵session

  • 設計以學生身份證號爲主鍵
  • 在業務上添加學生身份證號,不當心錄入錯誤
  • 主鍵修改是若是兩個相同是容許修改的。因此一旦參於業務,就可能存在一些問題
  • 主鍵通常只做爲條件,查詢,不參與修改,使用代理主鍵就和表當中的業務信息沒有關係

開發中爲何要使用代理主鍵多線程

  • 一旦天然主鍵參與到業務邏輯當中,後期有可能修改源代碼
  • 一個好的程序設計要知足開閉原則(Open Closed Principle)
    • 對程序的擴展是open開放的
    • 對修改源碼是close的

2、主鍵的生成策略

  • 在使用代理主鍵的過程中,儘可能要作到自動生成主鍵,不能讓用戶手動設置主鍵
  • 通常交給數據庫自動增加,讓程序生成惟一的標識
  • 在hibernate當中,爲了減小程序的編寫,內部提供了多種的主鍵生成策略

1. increment

  • 自動增長策略(long、short、int)
  • 原理
    • 首先先發送一條語句:select max(id) from 表
    • 而後讓id加1
  • 在單線程中使用,不要在多線程中使用
    • 兩個線程同時對數據庫當中的id字段查詢
    • 兩我的查詢的內容都是1
    • 其中一個確定會報錯

2. identity

  • 自動增加
  • 原理
    • 使用是數據庫底層的增加策略
    • 適用於有自動增加機制的數據庫
      • Mysql有自動增加
      • Oracle是沒有自動增加的:經過序列來完成這種效果的

3. sequence

  • 自動增加
  • 原理
    • 採用序列的方式
    • 必須得要支持序列
      • Oracle支持序列
      • Mysql不支持序列

4. uuid

  • 適用於字符串類型的主鍵
  • 使用hibernate中隨機生成字符串的主鍵

5. native

  • 本地策略
  • 在 identity 和 sequence 自動切換

6. assigned

  • hibernate不會幫你管理主鍵
  • 本身手動調用或經過程序來去生成主鍵

持久化

1、什麼是持久化

  • 將內存中的一個對象持久化到(存儲到)數據庫的過程
  • hibernate框架就是一個持久化的框架

2、什麼是持久化類

  • 一個Java類與數據庫創建的映射關係
  • 持久化類 = Java類 + 映射文件

3、持久化類編寫規則

1.對持久化類提供一個無參的構造方法

  • 底層會經過反射建立對象
  • 若是沒有無參構造,反射是沒法建立對象的

2.對內部私有的字段要提供get與set方法

  • 不提供的話。hibernate就沒法獲取對象的值

3.對象持久化類提供一個OID與數據庫表當中的主鍵對應

  • Java中經過對象的地址來區別是否爲同一個對象
  • 數據庫中經過主鍵來區別是不是同一條記錄
  • Hibernate中經過持久化類的OID屬性來區分是不是同一個對象

4.持久化類中的屬性儘可能使用包裝類型

  • 包裝類型的默認值爲NULL
  • 基本數據類型的默認值爲數字

5.持久化類不要使用final修飾

  • 跟延時加載有關係
  • 延時加載是Hibernate優化的手段
  • 返回的是一個代理對象
  • 使用動態代理 ,低層使用的是字節碼加強技術,繼承這個類來進行代理。
  • 若是使用了final,就不能被繼承,不能被繼承,代理對象就沒法建立,延時加載就無效了。

持久化類的劃分

  • Hibernate是持久層的框架,經過持久化類完成ORM操做
  • 持久化類:Java類+映射文件

Hibernate爲了更好的管理持久化類,將持久化類對象分爲三種狀態

1. 瞬時態

  • 沒有惟一的OID
  • 沒有被session管理
  • 這種對象咱們稱爲瞬時態對象

2.持久態

  • 有惟一的OID
  • 有被session管理
  • 這種對象咱們稱爲持久態對象

3.遊離態/託管態/離線態

  • 有惟一的OID
  • 沒有被session管理

三種狀態區分

1. 瞬時態

剛new出對象時,尚未設置id,尚未被session所管理。框架

2. 持久態

已經有了id,調用session方法,把對象給session,才被session所管理 。ide

添加到session以後, 對象一直處理持久態。當對象處理持久態時, 能夠自動更新數據庫。優化

持久態對象特徵
  • 自動更新數據,只要成爲持久態對象,不用調用update也會自動更新數據
  • 若是值和數據庫當中的值同樣, 就不會發送update
  • 原理:依賴了hibernate當中的一級緩存

3. 遊離態

把session關閉掉時close時,對象處理遊離態。ui

代碼演示

三種狀態之間的轉換

一級緩存

1、什麼是緩存

  • 緩存是一種優化的方式,分爲一級緩存和二級緩存。
  • 將數據存入到內存當中,使用的時候直接從緩存中獲取,不用直接到存儲源中取數據了。

2、一級緩存

  • session級別的緩存
  • 生命週期與Session一致:一級緩存是由Session中的一系列Java集合構成的
  • 是自帶的, 不可卸載

3、二級緩存

  • SessionFactory級別的緩存
  • 須要本身去配置,默認是開啓的,在企業當中通常都不用了,如今都 redis。

4、一級緩存特色

當應用程序用Session接口的Save(),update(),saveOrUpdate()時,若是session緩存中沒有相應的對象,就會自動的從數據庫查詢相應的信息,寫到緩存當中。

當調用Session接口的load,get()方法,以及Query接口的list iterator方法時, 會判斷緩存中是否存在該對象,有則返回, 不會查詢數據庫,若是緩存中沒有要查詢的對象,再到數據庫當中查詢對應的對象,並添加到一級緩存中。

當調用session.close方法時,緩存會被清空。

代碼:

5、一級緩存內部結構

一級緩存當中有一個區域:快照區

  • 使用id進行查詢數據庫,將查詢獲得的結果放置到session一級緩存中,同時複製一份數據,放置到session的快照中
  • 當使用tr.commit()的時候,同時清理session的一級緩存(flush)
  • 當清理session一級緩存的時候,會使用OID判斷一級緩存中對象和快照中的對象進行比對
  • 若是2個對象(一級緩存的對象和快照的對象)中的屬性發生變化,則執行update語句,此時更新數據庫,更新成一級緩存中的數據
  • 若是2個對象中的屬性不發生變化,此時不執行update語句

目的:確保和數據庫中的數據一致

清空一級緩存

  • clear():清空全部緩存
  • evict(obj):清空一個對象

事務管理

1、事務

  • 邏輯上的一組操做
  • 要麼全都成功,要麼全都失敗

2、事務特性

1. 原子性

事務不能分隔

2. 隔離性

執行一個事務時, 不該受到其它事務的干擾

  • 髒讀:一個事務讀取某一個事務未提交的數據
  • 不可重複讀:一個事務讀取取另外一個事務已經提交的update數據,致使在前一個事務屢次查詢的結果不同
  • 幻讀:一個事務讀取到別一個事務已經提交的insert數據,致使在前一個事務屢次查詢的結果不同

3. 持久性

事務完成後, 數據就持久到數據庫當中

4. 一致性

事務執行先後 ,數據的完整性要保持一致

3、事務的隔離級別

  • Read uncommitted
    • 全部問題都會發生
  • Read committed
    • 解決髒讀問題
  • Repeatable read
    • 解決髒讀和不可重複讀
  • Serializable
    • 解決全部問題,效率較低

4、Hibernate設置事務的隔離級別

  • 在覈心配置文件hibernate.cfg.xml當中
  • 經過數字來表明不一樣的隔離級別
<property name="hibernate.connection.isolation">4</property>

5、事務業務層鏈接

在業務層使用事務時,必須得要保證獲取事物的鏈接和dao層操做的鏈接是同一個,不然就管理了不對應的操做

1. 使用jdbc當中事務業務層處理方法

(1)向下傳遞

就開始在業務層先建立好一個鏈接,傳給dao層,讓dao層使用這個鏈接執行操做

(2)使用ThreadLocal對象

在service方法當中把建立的鏈接綁定到對應的threadLocal當中,在dao方法當中,經過當前的線程得到鏈接對象

2. hibernate當中處理方法

  • Hibernate框架,內部已經綁定好了ThreadLocal
  • 在SessionFactory中,提供了一個方法,getCurrentSession() 方法,獲取當前線程中的session
  • 此方法默認不能用,要經過配置完成
  • 在覈心配置文件(hibernate.cfg.xml)當中配置
<property name="current_session_context_class">thread</property>
  • 建立一個session綁定到當前線程
  • 經過它來操做時, 不須要 close,執行結束後, 會自動的close()
相關文章
相關標籤/搜索