Hibernate3 第二天

来源:http://www.cnblogs.com/beyondcj/archive/2017/01/10/6271024.html
-Advertisement-
Play Games

Hibernate3 第二天 第一天回顧: 三個準備 創建資料庫 準備po和hbm文件 準備靈魂文件hibernate.cfg.xml 七個步驟 1 載入配置文件Configuration 2 創建會話工廠SessionFactory 3 獲取連接Session 4 開啟事務Transaction ... ...


Hibernate3 第二天

第一天回顧:

  1. 三個準備
  • 創建資料庫
  • 準備po和hbm文件
  • 準備靈魂文件hibernate.cfg.xml
  1. 七個步驟
  • 1 載入配置文件Configuration
  • 2 創建會話工廠SessionFactory
  • 3 獲取連接Session
  • 4 開啟事務Transaction
  • 5 各種操作
  • 6 提交事務commit
  • 7 關閉連接close

     

     

    今天內容安排:

  1. Hibernate的持久化對象(PO)相關狀態和操作。(重點理解)
  • Hibernate持久化對象的狀態(3個)和轉換。
  • Session的一級緩存。
  • Session一級緩存的快照(snapshot)。
  1. 多表關聯映射配置和操作(重點應用)
  • 一對多關聯映射配置和操作、以及級聯配置、外鍵維護配置。
  • 多對多關聯映射配置和操作。

     

    學習目標:

  1. 掌握Hibernate的核心概念:PO的狀態+一級緩存和快照
  2. 掌握多表映射的配置、級聯配置和增刪改的操作(項目中使用)
  3. 逐步學會和習慣使用debug

 

  1. Hibernate的持久化對象相關概念和操作

    1. Hibernate持久化對象(po)的狀態和轉換

      1. 持久化對象的狀態

官方描述:

Hibernate 將操作的PO對象分為三種狀態:

  • 瞬時 (Transient )/ 臨時: 通常new 創建對象(持久化類),未與Session關聯,沒有OID
  • 持久 (Persistent) : 在資料庫存在對應實例擁有持久化標識OID與Session關聯(受session管理)
  • 脫管 (Detached)/游離:當Session關閉後,持久狀態對象與Session斷開關聯,稱為脫管對象,此時也持有OID

 

搭建測試環境:創建項目Hibernate3_day02

  1. 導入開發jar包(11個),將hibernate.cfg.xml、log4j.properties複製到src,修改Hibernate.cfg.xml的jdbc連接參數,導入hibernateUtils工具類。
  2. 創建包:cn.itcast.a_postate,在包中創建Customer類,代碼如下:

  3. 編寫hbm映射

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE hibernate-mapping PUBLIC

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

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

<hibernate-mapping>

    <!-- 配置java類與數據表的對應關係

     name:java類名

         table:表名

     -->

    <class name="cn.itcast.a_postate.Customer" table="t_customer">

        <!-- 配置主鍵 -->

        <id name="id">

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

        </id>

        <!-- 配置其他屬性 -->

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

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

    </class>

</hibernate-mapping>

 

  1. 在hibernate.cfg.xml載入映射配置

5 創建TestPOState類,描述對象的三狀態。

在類中編寫測試testSave方法:代碼如下:

@Test

    public void testSave(){

        //瞬時態:

        //特點:沒有OID,new出來的一個對象,不與session關聯,不受session管理,資料庫中沒有對應的記錄

        Customer customer = new Customer();

        customer.setName("rose");

        customer.setAge(18);

        System.out.println(customer);

        

        Session session = HibernateUtils.openSession();

        session.beginTransaction();

        

        //在save執行之前,customer都只是瞬時態

        //當save執行之後,customer就處於持久態

        session.save(customer);

        //持久態

//        /特點:有OID,資料庫存在對應的記錄,與session關聯,受session管理

        System.out.println(customer);

        session.getTransaction().commit();

        session.close();

        

        //只要session已關閉,那麼久處於脫管態

        //有OID,資料庫中存在對應的記錄,但是不與session關聯,不受session管理

        System.out.println(customer);

        

    }

 

 

三種狀態的區別分析:

  • 持久態和瞬時態、脫管態:容易區別,持久態主要特點是與Session關聯,而且資料庫中有對應記錄擁有OID,因此,只要與session關聯的就是持久態

瞬時態和脫管態:相同點是都和Session沒關聯,不同點是瞬時態沒有OID,而脫管態有OID。

 

【思考】

通過上述的分析,發現,瞬時態和脫管態對象就差一個OID,那麼瞬時態的對象中給主鍵ID屬性賦值後就是脫管態了麽?

未必!

首先,需要區分持久化標識OID對象中主鍵ID屬性的關係:

  • 在持久化之前,雖然有ID屬性,但資料庫中沒有對應的數據,那麼此時OID是null;
  • 在持久化之後,這個ID屬性值被插入資料庫中當主鍵了,資料庫中有對應的數據了,此時OID就有值了,而且與主鍵值保持一致性,比如類型、長度等。

因此:OID和PO對象中主鍵ID屬性的區別就是:資料庫存在不存在,如果存在就是OID,如果不存在,那就是個ID屬性而已。

 

瞬時態和脫管態的區別總結:

  • 脫管態對象:有持久化的標識oid,並且在資料庫中存在。
  • 瞬時態對象:無持久化標識oid,或者有id但在資料庫中不存在的。

 

例如:

Customer對象具有Id屬性值,如果資料庫中不存在,則該對象還是瞬時態對象,如果資料庫中存在,則認為是脫管態的。

 

【三者的區別最終總結】:

對於三者:在session中存在的,就是持久化對象不存在的就是瞬時或脫管對象

對於瞬時和脫管對象:有oid(持久化標識)的就脫管對象,沒有的就是瞬時對象

OID一定是與資料庫主鍵一一對應的

 

是否有持久化標識OID

session是否存在

資料庫中是否有

瞬時態對象-臨時狀態

n

n

n

持久態對象

y

y

y/(n:沒有提交)

脫管態對象-游離

y

n

y

 

  1. 持久化對象狀態的相互轉換

持久化對象狀態轉換圖(官方規範):

 

 

 

【分析】:(各狀態對象的獲取方式以及不同狀態之間轉換的方法介紹):

  • 瞬時對象:

    如何直接獲得 --- new 出來

    轉換到持久態 ---- save、saveOrUpdate 保存操作

    轉換到脫管態 ---- setId 設置OID持久化標識(這個id是資料庫中存在的)

  • 持久對象

    如何直接獲得 ---- 通過session查詢方法獲得 get、load、createQuery、createSQLQuery、createCriteria

    轉換到瞬時態 ---- delete 刪除操作 (數據表不存在對應記錄 )(其實還有id,只是不叫OID)

    轉換到脫管態 ---- close 關閉Session, evict、clear 從Session清除對象

  • 脫管對象

    如何直接獲得 ----- 無法直接獲得 ,必須通過瞬時對象、持久對象轉換獲得

    轉換到瞬時態 ---- 將id設置為 null,或者手動將資料庫的對應的數據刪掉或者將id修改成資料庫中不存在的

    轉換到持久態 ---- update、saveOrUpdate、lock (對象重新放入Session ,重新與session關聯)

 

在Hibernate所有的操作只認OID,如果兩個對象的OID一致,它就直接認為是同一個對象。

 

  1. Session的一級緩存(重點理解)

    1. 什麼是一級緩存?

又稱為:hibernate一級緩存、session緩存、session一級緩存

 

  • 緩存的概念:在記憶體上存儲一些數據

緩存的介質是一般是記憶體(硬碟),用來存放數據,當第一次查詢資料庫的時候,將數據放入緩存,當第二次繼續使用這些數據的時候,就不需要要查詢資料庫了,直接從緩存獲取,

 

 

  • 一級緩存概念:

在Session介面中實現了一系列的java集合,這些java集合構成了Session的緩存,只要Session的生命周期沒有結束,session中的數據也就不會被清空。

 

  • 緩存作用:

將數據緩存到記憶體或者硬碟上,訪問這些數據,直接從記憶體或硬碟載入數據,無需到資料庫查詢。

好處: 快! 降低資料庫壓力。

 

  • 一級緩存的生命周期:

Session中對象集合(map),在Session創建時,對象集合(map)也就創建,緩存保存了Session對象數據,當Session銷毀後,集合(map)銷毀, 一級緩存釋放 !

  • 什麼對象會被放入一級緩存?

只要是持久態對象,都會保存在一級緩存 (與session關聯的本質,就是將對象放入了一級緩存

 

一級緩存的作用:第一次get/load的時候,肯定會發出sql語句,查詢資料庫,(此時會將數據放入一級緩存),只要session不關閉,

第二次get/load的時候,直接從緩存中讀取數據,不會發出sql語句,查詢資料庫(這裡的數據指的是同一條記錄:OID相等)

 

【示例】證明一級緩存的存在性!

通過多次查詢同一個po對象數據,得到同一個對象,且第二次不再從資料庫查詢,證明一級緩存存在。

@Test

    public void testFirstCacheExist(){

        /**

         * 證明一級緩存的存在性

         * 證明思路:

         * 緩存的作用就是用來少查資料庫的,提高訪問速度

         * 第一步,通過get/load查詢數據,由於是第一次查詢,所以必然發出sql語句,查詢資料庫

         * 第二步,不關閉session,繼續使用當前的session去get/load數據,觀察是否發出sql語句

         * 如果不發出,表明是從一級緩存取出的數據

         */

        Session session = HibernateUtils.openSession();

        session.beginTransaction();

        

        //第一步:此時必然發出sql語句,然後自動將數據放入一級緩存

        Customer customer = (Customer) session.get(Customer.class, 1);

        System.out.println(customer);

        

        //第二步:此時不會發出sql語句,直接從一級緩存獲取數據

        Customer customer2 = (Customer) session.get(Customer.class, 1);

        System.out.println(customer2);

        

        session.getTransaction().commit();

        session.close();

    }

 

測試(同一個對象):

  1. 一級緩存的生命周期

一級緩存的生命周期就是session的生命周期,不能跨Session,可以說,一級緩存和session共存亡

【示例】

使用兩個不同Session來測試生命周期。(一級緩存和session共存亡)

@Test

    public void testFirstCachelifecycle(){

        /**

         * 一級緩存的聲明周期:與session同生命共存亡

         * 如何證明一級緩存的生命周期?

         * 只要證明數據不能跨session

         * 1 獲取session1,通過session1拿到customer對象,此時必然發出sql語句,關閉session1

         * 2 獲取session2,通過session2繼續抓取customer對象,觀察第二次是否發出sql語句

         * 如果發出,,表名session1銷毀的時候,把數據也銷毀了

         */

        Session session1 = HibernateUtils.openSession();

        session1.beginTransaction();

        

        //此時必然發出sql語句,因為是第一次查詢

        Customer customer = (Customer)session1.get(Customer.class, 1);

        

        System.out.println(customer);

        

//        此處如果需要查詢Customer,會發sql語句嗎?答:不會,直接走一級緩存

        //也能證明數據成功存入了一級緩存

        Customer customer2 = (Customer)session1.get(Customer.class, 1);

        System.out.println(customer2);

        

        session1.getTransaction().commit();

        session1.close();

        

        /**********第二次*********/

        Session session2 = HibernateUtils.openSession();

        session2.beginTransaction();

        

        //此時發sql語句嗎?答:發,因為session1中的數據跟隨session1一起銷毀了

        Customer customer3 = (Customer)session2.get(Customer.class, 1);

        System.out.println(customer3);

        

        session2.getTransaction().commit();

        session2.close();

        

        

    }

 

測試:

 

小結:緩存的作用,可以提高性能,減少資料庫查詢的頻率。

[補充:原則]所有通過hibernate操作(session操作)的對象都經過一級緩存。

一級緩存是無法關閉的!內置的!hibernate自己維護的!

 

  1. Session一級緩存的快照

    1. 什麼是一級緩存的快照(snapshot)

什麼是快照?

答:快照,是數據在記憶體中的副本,是資料庫中數據在記憶體中的映射。

 

如:

一句話:

快照跟資料庫數據保持一致

快照的作用就是用來更新數據的。

 

  1. 一級緩存快照的原理(圖)

採用快照技術進行更新,不需要手動的調用update 方法,完全是自動的發出update語句。

保正一級緩存、資料庫、快照的一致性

【註意】

  1. 持久態對象原則:po對象儘量保持與資料庫一一致。
  2. 當一級緩存和快照不一致的時候,會先發出update語句,將一級緩存同步到資料庫(發出update語句),然後當同步成功之後,再自動內部同步快照。保證三者的一致性。

 

  1. 一級緩存快照的能力

一級緩存的快照是由Hibernate來維護的,用戶可以更改一級緩存(PO對象的屬性值),無法手動更改快照!

快照的主要能力(作用)是:用來更新數據!當刷出緩存的時候,如果一級緩存和快照不一致,則更新資料庫數據。

【示例】

通過改變查詢出來的PO的屬性值,來查看一級緩存的更改;通過提交事務,來使用快照更新數據。

@Test

    public void testSnapShot(){

        /**

         * 證明快照的能力:自動更新數據

         * 1 從資料庫查找一個對象,改變對象的某個值,手動的flush,看控制台是否發出sql語句,

         * 如果控制台發出update語句,就可以表明快照的能力

         */

        Session session = HibernateUtils.openSession();

        session.beginTransaction();

        //get的時候,不光將數據放入一級緩存,還同時將數據同步到了快照中

        Customer customer = (Customer)session.get(Customer.class, 1);    

        

        System.out.println(customer);

        //修改customer對象的值

        customer.setName("lucy");

        

        //這個值是改變過後的值,是記憶體中的值

        System.out.println(customer);

        

        //提交事務

        //如果不手動flush,在事務commit的時候,會先flush,在commit

        session.getTransaction().commit();

        session.close();

        

        

    }

    

 

 

【能力擴展】快照可以用來更新數據,而且,可以用來更新部分數據

 

【問題】update也是更新數據,快照也是更新數據?兩個有什麼區別?

Update更新的時候,會將所有值都更新,如果有某個屬性沒有賦值,值將會被置空

 

快照符合我們修改的要求:先查後改

 

 

 

  1. 刷出緩存的時機

什麼叫刷出緩存?

Session能夠在某些時間點,按照緩存中對象的變化來執行相關的SQL語句,來同步更新資料庫,這一過程被成為刷出緩存(flush)。

 

通俗的說法:將一級緩存的數據同步到資料庫,就是刷出緩存

 

 

什麼情況下session會執行 flush操作?

 

刷新緩存的三個時機:

  • 事務提交commit():該方法先刷出緩存(session.flush()),然後再向資料庫提交事務。
  • 手動刷出flush():直接調用session.flush()。
  • 查詢操作:當Query查詢(get、load除外,這兩個會優先從一級緩存獲取數據)時,會去比較一級緩存和快照,如果數據一致,則去資料庫直接獲取數據,如果緩存中持久化對象的屬性已經發生了變化,(一級緩存和快照不一樣了),則先刷出緩存,發出update語句,然後查詢,以保證查詢結果能夠反映出持久化對象的最新狀態。(Query查詢數據不走一級緩存)

 

【補充理解】:

關於Hibernate如何識別同一個對象?

根據OID,

問題:假如先查詢出來一個對象oid是1001,資料庫主鍵也是1001,但其他欄位的屬性不一樣,那麼,再次查詢資料庫的數據出來的對象,和原來的對象是否是一個對象?

答案:是!

 

【示例】

1 、通過commit 的方式隱式的刷出緩存(證明略)

 

2 、通過flush的方式手動的刷出緩存

//採用flush的方式手動的刷出緩存

    @Test

    public void testflushcache2()

    {

        Session session = HibernateUtils.openSession();

        // 開啟 事務

        session.beginTransaction();

        

        //獲取數據

        Customer customer = (Customer)session.get(Customer.class, 1);

        

        System.out.println(customer);

          

        

        customer.setName("rose");

        

        //手動的flush,發出update語句,更新資料庫,並且同時更新快照

        session.flush();

        

        session.getTransaction().commit();

        //特點:在資料庫中存在對應的記錄,有OID,但是不受session管理

        session.close();

        

    }

 

 

 

3 、使用Query的時候,(不包含get、laod:原因:get和load的處理方式,是直接獲取緩存的數據,即使一級緩存和快照的數據不一致)

會去比較一級緩存和快照是否一致,如果一致,他直接去查詢(1條select語句)

當不一致了,會先發出update語句,更新資料庫,然後在查詢(1條update語句,1條select語句)

 

3.1 測試get和load 的處理方式

@Test

    public void testGetAndLoad_Cache(){

        /**

         * 證明get和load優先從緩存取數據,哪怕一級緩存和快照的數據不一致,

         * 它也是直接取緩存數據

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 專業定製三級分銷,微分銷網站系統開發建設無限級分銷三級分潤: 通過移動社交平臺(微信、微博、QQ空間),每個分銷商都可以無限級的發展自己的下屬分銷商,訂單成交後相關聯的上三級分銷商獲取自定的分潤。 自定義分紅規則 在自定義時間段完成銷售額、發展多少下屬分銷商等各項指標自定義分紅規則,獨特的自定義分紅 ...
  • 今天博客中就來聊一下Perfect框架的靜態文件的添加與訪問,路由的配置以及表單的提交。雖然官網上有聊靜態文件的訪問的部分,但是在使用Perfect框架來訪問靜態文件時還是有些點需要註意的,這些關鍵點在其官方文檔上並未提出。今天我們要做的事情就是通過瀏覽器訪問靜態文件,然後在靜態文件中使用form表 ...
  • 20170110問題解析請點擊今日問題下方的“【Java每日一題】20170111”查看(問題解析在公眾號首發,公眾號ID:weknow619) 今日問題: 請問主程式有無編譯錯誤?(點擊以下“【Java每日一題】20170111”查看20170110問題解析) 題目原發佈於公眾號、簡書:【Java ...
  • 進程相關的概念 程式與進程 程式,是指編譯好的二進位文件,在磁碟上,不占用系統資源(CPU、記憶體、打開的文件、設備、鎖等等)。 進程,是一個抽象的概念,與操作系統原理聯繫緊密。進程是活躍的程式,占用系統資源。在記憶體中執行(程式運行起來,產生一個進程)。 程式 --> 劇本(紙),進程 -->戲(舞臺 ...
  • 通過前面幾章,我們已經掌握了一些基本的開發知識,但是代碼結構比較簡單,缺乏統一的標準,模塊化,也缺乏統一的異常處理,這一章我們主要來學習如何封裝一個輕量級的MVC框架,規範以及簡化開發,並且提供類似php所見即所得的能力 統一入口 通常來說一個mvc框架會有一個統一的入口點,類似於spring mv ...
  • 最近用springmvc spring mybatis框架寫程式,請求成功並獲得數據,唯獨css樣式不能載入,但路徑正確,css文件編碼也是utf-8,用火狐debug總是顯示未請求到(都快懷疑自己寫路徑有問題了),今天終於搞定了。發現三種解決方式,但有一個我不知道什麼原因用不了。 方案一(個人認為 ...
  • Java 中的 static 使用之靜態方法 Java 中的 static 使用之靜態方法 1、 靜態方法中可以直接調用同類中的靜態成員,但不能直接調用非靜態成員。如: 如果希望在靜態方法中調用非靜態變數,可以通過創建類的對象,然後通過對象來訪問非靜態變數。如: 2、 在普通成員方法中,則可以直接訪 ...
  • 知識點: 文件讀,寫操作,if 判斷, for 迴圈 salary = input("輸入你的工資:") bought_list = [] product_list = {} with open("product_list","r",encoding="utf-8") as f1: for item ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...