Java三大框架之——Hibernate中的三種數據持久狀態和緩存機制

来源:http://www.cnblogs.com/hcl22/archive/2016/11/25/6100191.html
-Advertisement-
Play Games

Hibernate中的三種狀態 瞬時狀態:剛創建的對象還沒有被Session持久化、緩存中不存在這個對象的數據並且資料庫中沒有這個對象對應的數據為瞬時狀態這個時候是沒有OID。 持久狀態:對象經過Session持久化操作,緩存中存在這個對象的數據為持久狀態並且資料庫中存在這個對象對應的數據為持久狀態 ...


Hibernate中的三種狀態

    瞬時狀態:剛創建的對象還沒有被Session持久化、緩存中不存在這個對象的數據並且資料庫中沒有這個對象對應的數據為瞬時狀態這個時候是沒有OID   

  持久狀態:對象經過Session持久化操作,緩存中存在這個對象的數據為持久狀態並且資料庫中存在這個對象對應的數據為持久狀態這個時候有OID

  游離狀態:當Session關閉,緩存中不存在這個對象數據而資料庫中有這個對象的數據並且有OID為游離狀態。

  註:OID為了在系統中能夠找到所需對象,我們需要為每一個對象分配一個唯一的表示號。在關係資料庫中我們稱之為關鍵字,而在對象術語中,則叫做對象標識

(Object identifier-OID).通常OID在內部都使用一個或多個大整數表示,而在應用程式中則提供一個完整的類為其他類提供獲取、操作。

  Hibernate數據狀態圖:

    

 

需要註意的是:

 

      當對象的臨時狀態將變為持久化狀態。當對象在持久化狀態時,它一直位於 Session 的緩存中,對它的任何操作在事務提交時都將同步到資料庫,因此,對一個已經持久的對象調用 save() 或 update() 方法是沒有意義的。  

Student stu = new Strudnet();

stu.setCarId(“200234567”);

stu.setId(“100”);

// 打開 Session, 開啟事務

//將stu對象持久化操作
session.save(stu);

stu.setCardId(“20076548”);

//再次對stu對象進行持久化操作
session.save(stu); // 無效

session.update(stu); // 無效

// 提交事務,關閉 Session

 

 

 

Hibernate緩存機制

 

什麼是緩存?

  緩存是介於應用程式和物理數據源之間,其作用是為了降低應用程式對物理數據源訪問的頻次,從而提高了應用的運行性能。緩存內的數據是對物理數據源中的數據的複製,應用程式在運行時從緩存讀寫數據,在特定的時刻或事件會同步緩存和物理數據源的數據。  

 

緩存有什麼好處?

  緩存的好處是降低了資料庫的訪問次數,提高應用性能,減少了讀寫數據的時間

 

什麼時候適合用緩存?

  程式中經常用到一些不變的數據內容,從資料庫查出來以後不會去經常修改它而又經常要用到的就可以考慮做一個緩存,以後讀取就從緩存來讀取,而不必每次都去查詢資料庫。因為硬碟的速度比記憶體的速度慢的多。從而提高了程式的性能,緩存的出現就會為瞭解決這個問題

Hibernate中的緩存

  Hibernate中的緩存包括一級緩存(Session緩存)二級緩存(SessionFactory緩存)查詢緩存

 

    

    一級緩存(Session緩存)

    由於Session對象的生命周期通常對應一個資料庫事務或者一個應用事務,因此它的緩存是事務範圍的緩存。Session級緩存是必需的,不允許而且事實上也無法卸除。在Session級緩存中,持久化類的每個實例都具有唯一的OID。

    當應用程式調用Session的save()、update()、savaeOrUpdate()、get()或load(),以及調用查詢介面的list()、iterate()或filter()方法時,如果在Session緩存中還不存在相應的對象,Hibernate就會把該對象加入到第一級緩存中。

    當清理緩存時,Hibernate會根據緩存中對象的狀態變化來同步更新資料庫。

    Session為應用程式提供了兩個管理緩存的方法:evict(Object obj):從緩存中清除參數指定的持久化對象。clear():清空緩存中所有持久化對象。

 

    public static void testOneLeveCache(){
        Session session=HibernateUtil.getSession();
        //獲取持久化對象Dept
        Dept d1=(Dept)session.get(Dept.class, 10);
        //再次獲取持久化對象Dept
        Dept d2=(Dept)session.get(Dept.class, 10);    
        session.close();
    }

 

 

 

 

 

   通過Session的get()方法獲取到了Dept對象預設會將Dept對象保存到一級緩存中(Session緩存) 當第二次獲取的時候會先從一級緩存中查詢對應的對象(前提是不能清空或關閉Session否則一級緩存會清空或銷毀)如果一級緩存中存在相應的對象就不會到資料庫中查詢  所以只執行一次查詢的查詢代碼如下:

Hibernate: 
    select
        dept0_.DEPTNO as DEPTNO0_0_,
        dept0_.DNAME as DNAME0_0_,
        dept0_.LOC as LOC0_0_ 
    from
        SCOTT.DEPT dept0_ 
    where
        dept0_.DEPTNO=?

 

 

  如何清除一級緩存?

  通過session.clear();//清除所有緩存

    session.evict();//清除指定緩存

    public static void testOneLeveCache(){
        Session session=HibernateUtil.getSession();
        SessionFactory sf = HibernateUtil.getSessionFactory();
        //獲取持久化對象Dept
        Dept d1=(Dept)session.get(Dept.class, 10);
        session.clear();//清除所有緩存
        session.evict(d1);//清除指定緩存
        //再次獲取持久化對象Dept
        Dept d2=(Dept)session.get(Dept.class, 10);    
        session.close();
    }

 

使用session.evict(Object obj)會刪除指定的Bean所以當你查詢被你刪除二級緩存的Bean時也會執行兩條SQL語句

使用Session.clear()清除後會發現執行了兩條SQL語句:

Hibernate: 
    select
        dept0_.DEPTNO as DEPTNO0_0_,
        dept0_.DNAME as DNAME0_0_,
        dept0_.LOC as LOC0_0_ 
    from
        SCOTT.DEPT dept0_ 
    where
        dept0_.DEPTNO=?
Hibernate: 
    select
        dept0_.DEPTNO as DEPTNO0_0_,
        dept0_.DNAME as DNAME0_0_,
        dept0_.LOC as LOC0_0_ 
    from
        SCOTT.DEPT dept0_ 
    where
        dept0_.DEPTNO=?

 

  

 

 

    二級緩存(SessionFactory緩存)

  由於SessionFactory對象的生命周期和應用程式的整個過程對應,因此Hibernate二級緩存是進程範圍或者集群範圍的緩存,有可能出現併發問題,因此需要採用適當的併發訪問策略,該策略為被緩存的數據提供了事務隔離級別。

  save、update、saveOrupdate、load、get、list、query、Criteria方法都會填充二級緩存

  get、load、iterate會從二級緩存中取數據session.save(user)   

  如果user主鍵使用“native”生成,則不放入二級緩存.

  第二級緩存是可選的,是一個可配置的插件,預設下SessionFactory不會啟用這個插件。Hibernate提供了org.hibernate.cache.CacheProvider介面,它充當緩存插件與Hibernate之間的適配器。

 

Hibernate的二級緩存策略的一般過程如下:
   
1) 條件查詢的時候,總是發出一條select * from table_name where …. (選擇所有欄位)這樣的SQL語句查詢資料庫,一次獲得所有的數據對象。
    2) 把獲得的所有數據對象根據ID放入到第二級緩存中。
    3) 當Hibernate根據ID訪問數據對象的時候,首先從Session一級緩存中查;查不到,如果配置了二級緩存,那麼從二級緩存中查;查不到,再查詢資料庫,把結果按照ID放入到緩存。
    4) 刪除、更新、增加數據的時候,同時更新緩存。
  Hibernate的二級緩存策略,是針對於ID查詢的緩存策略,對於條件查詢則毫無作用。為此,Hibernate提供了針對條件查詢的查詢緩存(Query Cache)。

 

配置二級緩存(SessionFactory緩存)

  在hibernate.cfg.xml中配置以下代碼

    <!-- 開啟二級緩存 -->
    <property name="hibernate.cache.use_second_level_cache">true</property>
    <!-- 為hibernate指定二級緩存的實現類 -->
    <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>

 

  指明哪些類需要放入二級緩存,需要長期使用到的對象才有必要放入二級緩存放入二級緩存的方式有兩種:

    1.在hibernate.cfg.xml中配置

<class-cache class="entity.PetInfo" usage="read-only" /> //不允許更新緩存中的對象
<class-cache class="entity.PetInfo" usage="read-write" />  //允許更新緩存中的對象

 

    2.在Bean.hbm文件中配置

<hibernate-mapping>
    <class name="com.bdqn.entity.Dept" table="DEPT" schema="SCOTT"  >
        <cache usage="read-only"/>//將這個類放入二級緩存
        <id name="deptno" type="java.lang.Integer">
            <column name="DEPTNO" precision="2" scale="0" />
            <generator class="assigned"></generator>
        </id>
        <property name="dname" type="java.lang.String">
            <column name="DNAME" length="14" />
        </property>
    </class>
</hibernate-mapping>

 

  

  在ehcache.xml配置文件中可以設置緩存的最大數量、是否永久有效、時間等

<defaultCache
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        overflowToDisk="true"
        />

 

 

如何清除二級緩存?

  需要用SessionFactory來管理二級緩存代碼如下:

sessionFactory.evict(Entity.class);//清除所有Entity

sessionFactory.evict(Entity.class,id);//清除指定Entity
比如:
//用SessionFacotry管理二級緩存

SessionFactory factory=HibernateUtils.getSessionFactory();

//evict()把id為1的Student對象從二級緩存中清除.

factory.evict(Student.class, 1); 
//evict()清除所有二級緩存.

factory.evict(Student.class); 

 

 

 

什麼樣的數據適合存放到第二級緩存中?   
  1) 很少被修改的數據   
  2) 不是很重要的數據,允許出現偶爾併發的數據   
  3) 不會被併發訪問的數據   
  4) 常量數據   
不適合存放到第二級緩存的數據?   
  1) 經常被修改的數據   
  2) 絕對不允許出現併發訪問的數據,如財務數據,絕對不允許出現併發   
  3) 與其他應用共用的數據。

 

 

  查詢緩存(Query Cache)

   hibernate的查詢緩存是主要是針對普通屬性結果集的緩存, 而對於實體對象的結果集只緩存id。

   在一級緩存,二級緩存和查詢緩存都打開的情況下作查詢操作時這樣的:

    查詢普通屬性,會先到查詢緩存中取,如果沒有,則查詢資料庫;查詢實體,會先到查詢緩存中取id,如果有,則根據id到緩存(一級/二級)中取實體,如果緩存中取不到實體,再查詢資料庫。

 

         在hibernate.cfg.xml配置文件中,開啟查詢緩存    

<!-- 是否開啟查詢緩存,true開啟查詢緩存,false關閉查詢緩存 -->
<property name="cache.use_query_cache">true</property>

 

    開啟查詢緩存後還需要在程式中進行啟用查詢緩存

public static void testQueryCache(){
        Session session=HibernateUtil.getSession();
        String hql="from Emp as e";
        Query query=session.createQuery(hql);
        query.setCacheable(true);//啟用查詢緩存(二級緩存)
        List<Emp> empList=query.list();
        session.close();
}        

 

查詢緩存是基於二級緩存機制如果根據Bean的屬性查詢可以不開啟二級緩存代碼如下:

      session = HibernateUtils.getSession(); 
      t = session.beginTransaction(); 
      Query query = session.createQuery("select s.name from Student s"); 
      //啟用查詢緩存    
      query.setCacheable(true); 
      List<String> names = query.list(); 
      for (Iterator<String> it = names.iterator(); it.hasNext();) { 
        String name = it.next(); 
        System.out.println(name); 
      } 
      System.out.println("================================"); 
      query = session.createQuery("select s.name from Student s"); 
      //啟用查詢緩存 
      query.setCacheable(true); 
      //沒有發出查詢語句,因為這裡使用的查詢緩存 
      names = query.list(); 
      for (Iterator<String> it = names.iterator(); it.hasNext();) { 
        String name = it.next(); 
        System.out.println(name); 
      } 
      t.commit(); 

 


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

-Advertisement-
Play Games
更多相關文章
  • 一、前言 1.0、由於沒有寫過那種通用爬蟲的框架,就四處搜了一下,也找到很多資料,這裡就採用了其中一個大神介紹的框架模式。具體引用地址我忘記了,這裡就不貼出來了。 2.0、之前說的驗證碼模塊也停了,到時候集合在這個分類一面一起說 二、正文 2.1、框架設計圖 2.2、由上面這張圖可以看出各個模塊之間 ...
  • 感謝您的閱讀。喜歡的、有用的就請大哥大嫂們高抬貴手“推薦一下”吧!你的精神支持是博主強大的寫作動力以及轉載收藏動力。歡迎轉載! 版權聲明:本文原創發表於 【請點擊連接前往】 ,未經作者同意必須保留此段聲明!如有問題請聯繫我,侵立刪,謝謝! 我的博客:http://www.cnblogs.com/GJ ...
  • 完善了下 文件中的文件及文件夾中的複製!如果有更優解決方案請不吝指教 protected void FileDepthCopy(string source, string target) { if (Directory.Exists(source))//判斷源文件是否存在 { if (!Direct ...
  • 常用的一些開源組件整理: 導出Excel報表的插件:NOPI.dll(基於微軟OpenXml實現)開源的作業調度和自動任務框架:Quartz.NET用於大數據搜索引擎的全文檢索框架:Lucene.net微軟針對企業級應用開發的最佳實踐組件:Enterprise Library 5.0國外一個牛人寫的 ...
  • MVVM是一個比較熱門的開發框架,儘管已經出現很久了,仍然比較受歡迎。MVVM框架包括: M:Model;Model指的是數據模型,例如你要在頁面展示聯繫人信息,那麼Model就是聯繫人的模型,包括聯繫人的名字,電話號碼,頭像等。。。 V:View;View指的是展示的頁面,比如你所現在看到的這篇文 ...
  • 在項目開發過程中,有時會需要用到調用第三方程式實現本系統的某一些功能,例如本文中需要使用到的swftools插件,那麼如何在程式中使用這個插件,並且該插件是如何將PDF文件轉化為SWF文件的呢?接下來就會做一個簡單的介紹。 在.NET平臺中,對C#提供了一個操作對本地和遠程的訪問進程,使能夠啟動和停 ...
  • 本次活動,只是一個嘗試,也許效果好,也許效果差,但不嘗試一下,又怎麼知道呢~~~~最後謝謝大伙的支持! ...
  • 1、類圖 2、創建項目 ………………………… 3、 VisualComponent:抽象界面構件類,充當抽象構件類 為了突出與模式相關的核心代碼,咋基本實例中對空間代碼進行了簡化。 namespace DecoratorSample { /// <summary> /// 抽象構件類 /// </s ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...