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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...