<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    備注學院

    LuLu

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      5 隨筆 :: 50 文章 :: 16 評論 :: 0 Trackbacks

    前言

    本文探討Jive(曾經開源的Java論壇)HibernateJava開源持久層)的數據庫對象的緩存策略,并闡述作者本人的LightorJava開源持久層)采用的數據庫對象緩存策略。

    本文的探討基于以前開源的Jive代碼,Hibernate2.1.7源碼,和作者本人的Lightor代碼。

    本文用ID (Identifier的縮寫)來代表數據記錄的關鍵字。

    數據對象查詢一般分為兩種:條件查詢,返回一個滿足條件的數據對象列表; ID查詢,返回ID對應的數據對象。

    本文主要探討“條件查詢”和“ID查詢”這兩種情況的緩存策略。

    本文只探討一個JVM內的數據緩存策略,不涉及分布式緩存;本文只探討對應單表的數據對象的緩存,不涉及關聯表對象的情況。

    Jive的緩存策略

    1Jive的緩存策略的過程描述

    (1)條件查詢的時候,Jive select id from table_name where …. (只選擇ID字段)這樣的SQL語句查詢數據庫,來獲得一個ID列表。

    (2) Jive根據ID列表中的每個ID,首先查看緩存中是否存在對應ID的數據對象:如果存在,那么直接取出,加入到 結果列表中;如果不存在,那么通過一條select * from table_name where id = {ID value} 這樣的SQL查詢數據庫,取出對應的數據對象,放入到結果列表,并把這個數據對象按照ID放入到緩存中。

    (3) ID查詢的時候,Jive執行類似第(2)步的過程,先從緩存中查找該ID,查不到,再查詢數據庫,然后把結果放入到緩存。

    (4) 刪除、更新、增加數據的時候,同時更新緩存。

    2Jive緩存策略的優點:

    (1) ID查詢的時候,如果該ID已經存在于緩存中,那么可以直接取出。節省了一條數據庫查詢。

    (2) 當多次條件查詢的結果集相交的情況下,交集里面的數據對象不用重復從數據庫整個獲取,直接從緩存中獲取即可。

    比如,第一次查詢的ID列表為{1, 2},然后根據ID列表的ID從數據庫中一個一個取出數據對象,結果集為{a(id = 1),  b(id = 2)}

    下一次查詢的ID列表為{2, 3},由于ID = 2的數據對象已經存在于緩存中,那么只要從數據庫中取出ID = 3的數據對象即可。

    3Jive緩存策略的缺點:

    (1) 在根據條件查找數據對象列表的過程中,DAO的第(1)步用來獲得ID列表的那一次數據庫查詢,是必不可少的。

    (2) 如果第(1)步返回的ID列表中有nID,在最壞的命中率(緩存中一個對應ID都沒有)情況下,Jive還要再查詢n次數據庫。最壞情況下,共需要n + 1數據庫查詢。

    二、Hibernate二級緩存策略

    HibernateSession類包裝了數據庫連接從打開到關閉的過程。

    Session內部維護一個數據對象集合,包括了本Session內選取的、操作的數據對象。這稱為Session內部緩存,是Hibernate的第一級最快緩存,屬于Hibernate的既定行為,不需要進行配置(也沒有辦法配置 :-)

    Session的生命期很短,存在于Session內部的第一級最快緩存的生命期當然也很短,命中率自然也很低。當然,這個Session內部緩存的主要作用是保持Session內部數據狀態同步。

    如果需要跨Session的命中率較高的全局緩存,那么必須對Hibernate進行二級緩存配置。一般來說,同樣數據類型(Class)的數據對象,共用一個二級緩存(或其中的同一塊)。

    1Hibernate二級緩存策略的過程描述:

    (1)條件查詢的時候,總是發出一條select * from table_name where …. (選擇所有字段)這樣的SQL語句查詢數據庫,一次獲得所有的數據對象。

    (2) 把獲得的所有數據對象根據ID放入到第二級緩存中。

    (3) Hibernate根據ID訪問數據對象的時候,首先從Session一級緩存中查;查不到,如果配置了二級緩存,那么從二級緩存中查;查不到,再查詢數據庫,把結果按照ID放入到緩存。

    (4) 刪除、更新、增加數據的時候,同時更新緩存。

     

    2Hibernate二級緩存策略的優點:

    (1) 具有Jive緩存策略同樣的第(1)條優點:ID查詢的時候,如果該ID已經存在于緩存中,那么可以直接取出。節省了一條數據庫查詢。

    (2) 不具有Jive緩存策略的第(2)條缺點,即hibernate不會有最壞情況下的 n + 1次數據庫查詢。

    3Hibernate二級緩存策略的缺點:

    (1) Jive緩存策略的第(1)條缺點一樣,條件查詢的時候,第(1)步的數據庫查詢語句是不可少的。而且Hibernate選擇所有的字段,比只選擇ID字段花費的時間和空間都多。

    (2) 不具備Jive緩存策略的第(2)條優點。條件查詢的時候,必須把數據庫對象從數據庫中整個取出,即使該數據庫的ID已經存在于緩存中。

    三、HibernateQuery緩存策略

    可以看到,Jive緩存和Hibernate的二級緩存策略,都只是針對于ID查詢的緩存策略,對于條件查詢則毫無作用。(盡管Jive緩存的第(2)個優點,能夠避免重復從數據庫獲取同一個ID對應的數據對象,但select id from …這條數據庫查詢是每次條件查詢都必不可少的)。

    為此,Hibernate提供了針對條件查詢的Query緩存。

    1HibernateQuery緩存策略的過程描述:

    (1) 條件查詢的請求一般都包括如下信息:SQL, SQL需要的參數,記錄范圍(起始位置rowStart,最大記錄個數maxRows),等。

    (2) Hibernate首先根據這些信息組成一個Query Key,根據這個Query KeyQuery緩存中查找對應的結果列表。如果存在,那么返回這個結果列表;如果不存在,查詢數據庫,獲取結果列表,把整個結果列表根據Query Key放入到Query緩存中。

    (3) Query Key中的SQL涉及到一些表名,如果這些表的任何數據發生修改、刪除、增加等操作,這些相關的Query Key都要從緩存中清空。

    2HibernateQuery緩存策略的優點

    (1) 條件查詢的時候,如果Query Key已經存在于緩存,那么不需要再查詢數據庫。命中的情況下,一次數據庫查詢也不需要。

    3HibernateQuery緩存策略的缺點

    (1) 條件查詢涉及到的表中,如果有任何一條記錄增加、刪除、或改變,那么緩存中所有和該表相關的Query Key都會失效。

    比如,有這樣幾組Query Key,它們的SQL里面都包括table1

    SQL = select * from table1 where c1 = ? ….,  parameter = 1, rowStart = 11, maxRows = 20.

    SQL = select * from table1 where c1 = ? ….,  parameter = 1, rowStart = 21, maxRows = 20.

    SQL = select * from table1 where c1 = ? …..,  parameter = 2, rowStart = 11, maxRows = 20.

    SQL = select * from table1 where c1 = ? …..,  parameter = 2, rowStart = 11, maxRows = 20.

    SQL = select * from table1 where c2 = ? ….,  parameter = ‘abc’, rowStart = 11, maxRows = 20.

     

    table1的任何數據對象(任何字段)改變、增加、刪除的時候,這些Query Key對應的結果集都不能保證沒有發生變化。

    很難做到根據數據對象的改動精確判斷哪些Query Key對應的結果集受到影響。最簡單的實現方法,就是清空所有SQL包含table1Query Key

     

    (2) Query緩存中,Query Key對應的是數據對象列表,假如不同的Query Key對應的數據對象列表有交集,那么,交集部分的數據對象就是重復存儲的。

    比如,Query Key 1對應的數據對象列表為{a(id = 1), b(id = 2)}Query Key 2對應的數據對象列表為{a(id = 1), c(id = 3)},這個a就在兩個List同時存在了兩份。

    4二級緩存和Query緩存同步的困惑

    假如,Query緩存中,一個Query Key對應的結果列表為{a (id = 1) , b (id = 2), c (id = 3)}; 二級緩存里面有也id = 1對應的數據對象a

    這兩個數據對象a之間是什么關系?能夠保持狀態同步嗎?

    我閱讀Hibernate的相關源碼,沒有發現兩個緩存之間的這種同步關系。

    或者兩者之間毫無關系。就像我上面所說的,只要表數據發生變化,相關的Query Key都要被清空。所以不用考慮同步問題?

    四、Lightor的緩存策略

    Lightor是我做的Java開源持久層框架。Lightor的意思是,Lightweight O/RHibernateJDOEJB CMP這些持久層框架,都是LayerLightor算不上Layer,而只是一個Helper。這里的O/R意思不是Object/Relational,而是Object/ResultSet的意思。:-)

    Lightor的緩存策略,主要參照Hibernate的緩存思路,Lightor的緩存也分為 Query緩存和ID緩存。但其中有一點不同,兩者之間并不是毫無聯系的,而是相互關聯的。

    1Lightor的緩存策略的過程描述:

    (1) 條件查詢的請求一般都包括如下信息:SQL, 對應SQL的參數,起始記錄位置(rowStart),最大記錄個數(maxRows),等。

    (2) Lightor首先根據這些信息組成一個Query Key,根據這個Query KeyQuery緩存中查找對應的結果ID列表。注意,這里獲取的是ID列表。

    如果結果ID列表存在于Query緩存,那么根據這個ID列表的每個ID,到ID緩存中取對應的數據對象。如果所有ID對應的數據對象都找到,那個返回這個數據對象結果列表。注意,這里獲取的是整個數據對象(所有字段)的列表。

    如果結果ID列表不存在于Query緩存,或者結果ID列表中的某一個ID不存在于ID緩存,那么,就查詢數據庫,獲取結果列表。然后,把獲取的每個數據對象按照ID放入到ID緩存;并組裝成一個ID列表,按照Query Key存放到Query緩存中。注意,這里是把ID列表,而不是整個對象列表,放入到Query緩存中。

    (3) ID查詢的時候,Lightor先從ID緩存中查找該ID,如果不存在,那么查詢數據庫,把結果放入ID緩存。

    (4) Query Key中的SQL涉及到一些表名,如果這些表的任何數據發生修改、刪除、增加等操作,這些相關的Query Key都要從緩存中清空。

    2Lightor的緩存策略的優點

    (1) LightorID緩存具有Jive緩存,和Hibernate二級ID緩存的優點。ID查詢的時候,如果該ID已經存在于緩存中,那么可以直接取出。節省了一條數據庫查詢。

    (2) LightorQuery緩存具有HibernateQuery緩存的優點。條件查詢的時候,如果Query Key已經存在于緩存,那么不需要再查詢數據庫。命中的情況下,一次數據庫查詢也不需要。

    (3) LightorQuery緩存中,Query Key對應的是ID列表,而不是數據對象列表,真正的數據對象只存在于ID緩存中。所以,不同的Query Key對應的ID列表如果有交集,ID對應的數據對象也不會在ID緩存中重復存儲。

    (4) Lightor的緩存也沒有Jive緩存的最壞情況n + 1次數據庫查詢缺點。

    3Lightor的緩存策略的缺點

    (1) LightorQuery緩存具有HibernateQuery緩存的缺點。條件查詢涉及到的表中,如果有任何一條記錄增加、刪除、或改變,那么緩存中所有和該表相關的Query Key都會失效。

    (2) LightorID緩存也具有hibernate的二級ID緩存具有的缺點。條件查詢的時候,即使ID已經存在于緩存中,也需要重新把數據對象整個從數據庫取出,放入到緩存中。

    五、Query Key的效率

    Query緩存的Query Key的空間和時間開銷比較大。

    Query Key里面存放的東西不少,SQL, 參數,范圍(起始,個數)。

    這里面最大的東西就是SQL。又占地方,又花時間(hashCode, equals)。

    Query Key最關鍵的兩個方法是hashCodeequals,重點是SQLhashCodeequals

     

    Lightor的做法是,由于Lightor直接使用SQL,不用HQLOQL之類,所以推薦盡量使用static final StringSQL,能夠節省空間和時間,以至于Query Key的效率能夠相當于ID Key的效率。

    至于HibernateQueryKey,有興趣的讀者可以去下載閱讀Hibernate的各個版本的源代碼,跟蹤一下QueryKey的實現優化過程。

    六、總結

    這里列一個表,綜合表示Jive, Hibernate, Lightor的緩存策略的特征。

     

    N + 1問題

    重復ID緩存問題

    Query緩存支持

    Jive緩存

    不支持

    Hibernate緩存

    支持

    Lightor緩存

    支持

     

    注:

    “重復ID緩存問題”的含義是,每次條件查詢,不是只取ID列表,而是取出完整對象(所有字段)的列表。這樣,同一個ID對應的數據對象,即使在緩存中已經存在,也可能被重新放入緩存。參見相關緩存的缺點描述。

    “重復ID緩存問題”的負面效應到底有多大,就看你的select id from …(只選擇ID)比你的 select * from … (選擇所有字段)快多少。主要影響因素是,字段的個數,字段值的長度,與數據庫服務器之間網絡傳輸速度。

    不管怎么說,即使選擇所有字段,也只是一次數據庫查詢。而N + 1問題帶來的可能最壞的負面效應(N + 1次數據查詢)卻是非常大的。

    選擇緩存策略的時候,應根據這些情況發生的概率和正負面效應進行取舍。

    from:http://blog.csdn.net/buaawhl/archive/2004/12/21/224184.aspx

    posted on 2007-11-18 22:23 smildlzj 閱讀(277) 評論(0)  編輯  收藏 所屬分類: Java
    主站蜘蛛池模板: 国产精彩免费视频| 亚洲精品无码国产片| 91精品全国免费观看青青| 无码日韩人妻AV一区免费l| 免费看无码自慰一区二区| 久久aa毛片免费播放嗯啊| 亚洲av永久无码精品漫画| 国产午夜精品免费一区二区三区| 青青草a免费线观a| 国产性生交xxxxx免费| 国产亚洲精彩视频| 亚洲人色大成年网站在线观看| 国产成人亚洲精品蜜芽影院| 日韩中文无码有码免费视频 | 午夜国产精品免费观看| 亚洲一区在线观看视频| 日本免费一本天堂在线| 又硬又粗又长又爽免费看| 色婷婷7777免费视频在线观看 | 67pao强力打造国产免费| 久久久久亚洲AV成人网人人网站 | 边摸边吃奶边做爽免费视频99| 99re这里有免费视频精品| 午夜爱爱免费视频| 韩国亚洲伊人久久综合影院| 免费看h片的网站| 亚洲av无码偷拍在线观看| 国产亚洲日韩在线三区| 亚洲免费闲人蜜桃| 亚洲宅男永久在线| 在线免费视频一区| 在线综合亚洲中文精品| 亚洲高清视频免费| 亚洲专区先锋影音| 国产色爽女小说免费看| 国内少妇偷人精品视频免费| 亚洲国产另类久久久精品黑人 | 在线观看视频免费国语| 国产黄片不卡免费| 337p日本欧洲亚洲大胆色噜噜| 日本免费中文视频|