效能最佳化之Hibernate緩衝講解、應用和調優

來源:互聯網
上載者:User

近來坤哥推薦我我們一款效能監控、調優工具——JavaMelody,通過它讓我覺得項目最佳化是看得見摸得著的,最佳化有了針對性。而無論是對於分布式,還是非分布,緩衝是提示效能的有效工具。

資料層是EJB3.0實現的,而EJB3.0內部也是通過Hibernate實現的,而Hibernate本身提供了很好的緩衝機制,我們只需要學會使用它駕馭它就夠了。

緩衝的機能可以簡單理解為將從資料庫中訪問的資料放在記憶體中,在以後再次使用到這些資料時可以直接從記憶體中讀取而不必要再次訪問資料庫,盡量減少和資料庫的互動提高效能。

概念講解

在hibernate中提供了二種緩衝機制:一級緩衝、二級緩衝,因為二級緩衝策略是針對於ID查詢的緩衝策略,對於條件查詢則毫無作用,為此,Hibernate提供了針對條件查詢的Query Cache(查詢快取)。

一、一級緩衝:

一級緩衝是hibernate內建的,不受使用者幹預,其生命週期和session的生命週期一致,當前session一旦關閉,一級緩衝就會消失,因此,一級緩衝也叫session緩衝或者事務級緩衝,一級緩衝只儲存實體物件,不會緩衝一般的對象屬性,即:當獲得對象後,就將該對象緩衝起來,如果在同一個session中再去擷取這個對象時,它會先判斷緩衝中有沒有這個對象的ID,如果有,就直接從緩衝中取出,否則,則去訪問資料庫,取了以後同時會將這個對象緩衝起來。

二、二級緩衝:

二級緩衝也稱為進程緩衝或者sessionFactory級的緩衝,它可以被所有的session共用,二級緩衝的生命週期和sessionFactory的生命週期一致,二級緩衝也是只儲存實體物件

二級緩衝的一般過程如下:

①:條件查詢的時候,擷取查詢到的實體物件

②:把獲得到的所有資料對象根據ID放到二級緩衝中

③:當Hibernate根據ID訪問資料對象時,首先從sesison的一級緩衝中查,查不到的時候如果配置了二級緩衝,會從二級緩衝中尋找,如果還查不到,再查詢資料庫,把結果按照ID放入到緩衝中

④:進行delete、update、add操作時會同時更新緩衝

三、查詢快取:

查詢快取是對普通屬性結果集的緩衝,對實體物件的結果集只緩衝id,對於經常使用的查詢語句,如果啟用了查詢快取,當第一次執行查詢語句時,Hibernate會把查詢結果存放在二級緩衝中,以後再次執行該查詢語句時,只需從緩衝中獲得查詢結果,從而提高查詢效能,查詢快取中以索引值對的方式儲存的,key鍵為查詢的條件陳述式(具體的key規則應該是:類名+方法名+參數列表),value為查詢之後等到的結果集的ID列表

查詢快取的一般過程如下:

①:Query Cache儲存了之前查詢執行過的SelectSQL,以及結果集等資訊組成一個Query Key

②:當再次遇到查詢請求的時候,就會根據QueryKey從QueryCache中找,找到就返回,但當資料表發生資料變動的話,hbiernate就會自動清除QueryCache中對應的Query Key

我們從查詢快取的策略中可以看出,Query Cache只有在特定的條件下才會發揮作用,而且要求相當嚴格:

①:完全相同的SelectSQL重複執行

②:重複執行期間,QueryKey對應的資料表不能有資料變動

啟用緩衝的配置

EJB中配置查詢快取和二級緩衝

1、在persistence.xml中啟用緩衝
<persistence-unitname="gxpt-qx-entity" transaction-type="JTA" ><!--對jpa進行效能測試 --><provider>net.bull.javamelody.JpaPersistence</provider>                  <jta-data-source>java:/MySqlDS</jta-data-source>                 <!--<jta-data-source>java:/MyOracleDS</jta-data-source>   -->                                  <properties>                           <!-- <propertyname="hibernate.dialect"value="org.hibernate.dialect.Oracle10gDialect"/> -->                          <propertyname="hibernate.dialect"value="org.hibernate.dialect.MySQLDialect"/><propertyname="hibernate.hbm2ddl.auto" value="update" /><propertyname="hibernate.show_sql" value="true" /> <!--指定二級緩衝產品的供應商 --><propertyname="hibernate.cache.provider_class"value="net.sf.ehcache.hibernate.SingletonEhCacheProvider"/><!--                        <propertyname="hibernate.cache.region.factory_class"value="org.hibernate.cache.ehcache.EhCacheRegionFactory"/>--><!--開啟二級緩衝 --><propertyname="hibernate.cache.use_second_level_cache"value="true"/><!--開啟查詢快取 --><propertyname="hibernate.cache.use_query_cache"value="true"/> <!--指定緩衝設定檔位置   --><propertyname="hibernate.cache.provider_configuration_file_resource_path"value="/ehcache.xml"/>                  </properties></persistence-unit>
2、通過註解指定User類使用二級緩衝
@Entity@Table(name="tq_user")@Cache(usage=CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)publicclass User
3、開啟查詢快取,除了在persistence.xml中有以上配置外,還需要在底層代碼手動開啟查詢快取

query.setHint("org.hibernate.cacheable", true);

或者query.setCacheable(true);

效能測試通過sql語句 

1、二級緩衝關閉時,查詢快取開啟和關閉情況對比*****普通屬性查詢

public String myCache() {        List<String> strings = this.userServiceImpl                .search("selectu.username from User u where id<4 order by id asc");        for (String str : strings){           System.out.println("username:" + str);        }         System.out.println("===================================");        List<String> strings2 =this.userServiceImpl                .search("select u.usernamefrom User u where id<4 order by id asc");        for (String str : strings2){           System.out.println("username:" + str);        }        return "/mycache";    } 

當前二級緩衝為關閉狀態,看看查詢快取關閉時的查詢結果:

  public List<String> search(Stringhql) {        List<String> rtnStrs = newArrayList<String>();        try {           Session session = this.sessionFactory.openSession();            session.beginTransaction();            Query query = session.createQuery(hql);            //query.setCacheable(true);//手動開啟查詢快取            rtnStrs =(List<String>) query.list();            session.getTransaction().commit();        } catch (Exception e){            System.out.println("DAO層根據HQL語句查詢失敗");        }        return rtnStrs;    }

上面代碼中屏蔽了query.setCacheable(true)。

關閉二級緩衝、關閉查詢快取 運行如下:

 

開啟查詢快取、關閉二級緩衝運行如下

結論:對於查詢普通屬性,無論二級緩衝是否開啟,只要開啟了查詢快取,當兩次執行的sql語句相同時,第二次不會發出sql語句,直接從記憶體中擷取。

2、查詢快取開啟時,二級緩衝開啟和關閉情況對比*******查詢實體物件

/**     * 查詢快取開啟,二級緩衝關閉*******查詢實體物件     *     *運行結果:如果關閉查詢快取和二級緩衝,在兩次查詢時都發出sql語句,此時為兩條查詢語句     *     *運行結果:如果開啟查詢快取,關閉二級緩衝,第二次會發出根據ID查詢實體的n條查詢語句     *     *運行結論:第一次執行list時,會把查詢對象的ID緩衝到查詢快取中,第二次執行list時(兩次的查詢SQL語句相同),會遍曆查詢快取中的ID到     * (一級、二級)緩衝裡找實體物件, 此時沒有,則發出查詢語句到資料庫中查詢     *    */        publicString mycache3() {List<User>users1 = this.userServiceImpl.search();           for(User u : users1) {              System.out.println("users1:username:"+ u.getUsername());          }   System.out.println("===============");         List<User> users2 =this.userServiceImpl.search();        for (User u : users2) {           System.out.println("users2:usersname:" + u.getUsername());        }return"/mycache";    }

開啟查詢快取、關閉二級緩衝 運行如下:(兩次都發出sql,而且第二次發出n條語句)

 

開啟查詢快取、關閉二級緩衝 運行如下(只發出一條語句)

 

總結:

(1)、當只是用hibernate查詢快取,而關閉二級緩衝的時候:

①如果查詢的是部分屬性結果集,那麼當第二次查詢的時候就不會發出SQL語句,直接從Hibernate查詢快取中取資料

②如果查詢的是實體結果集(eg.from User)這個HQL,那麼查詢出來的實體,首先hibernate查詢快取存放實體的ID,第二次查詢的時候,就到hibernate查詢快取中取出ID一條一條的到資料庫查詢,這樣將發出N條SQL語句,造成SQL泛濫。所以,在使用查詢快取的時候,最好配合開啟二級緩衝。

(2)、當開啟Hibernate查詢快取和二級緩衝的時候:

①如果查詢的是部分屬性結果集,這個和上面只用hbiernate查詢快取而關閉二級緩衝的時候一致,因為不涉及實體,不會用到二級緩衝。

②如果查詢的是實體結果集,那麼查詢出來的實體首先在查詢快取中存放實體的ID,並將實體物件儲存到二級緩衝中,第二次查詢的時候,就到hibernate查詢快取中取ID,根據ID去二級緩衝中匹配資料,如果有資料就不會發出sql語句,如果都有,第二次查詢一條SQL語句都不會發出,直接從二級緩衝中取資料。

通過Javamelody

JavaMelody能夠在運行環境中監測Java或Java EE應用程式伺服器。並以圖表的形式顯示:Java記憶體和Java CPU使用方式,使用者Session數量,JDBC串連數,和http請求、sql請求、jsp頁面與業務介面方法(EJB3、Spring、Guice)的執行數量,平均執行時間,錯誤百分比等。

坤哥部落格有介紹Java項目效能監控和調優工具-Javamelody

監控項目緩衝個數

這是本次開發的許可權項目中的緩衝,共有12個,其中紅色部分分別為二級緩衝和查詢快取

對spring的監控

加緩衝情況

不加緩衝情況

根據統計結果,發現緩衝的確可以提高效能。

但是有時候使用了緩衝反而效能會降低,比如update方法,因為資料發生變更後,hibernate需要保持緩衝和資料庫兩份的資料同步,所以加上緩衝後,update效能降低,add、delete操作也是相同的道理。

所以緩衝適用於在項目中存在大量查詢的情況,否則是沒必要適用的。

小結

在想項目之所以很吸引自己,很重要的一點是因為我們在使用各種各樣的工具,包括在此提到的緩衝、javamelody,正如“君子生非異也,善假於物也”,更多工具的使用,會在後面詳細介紹。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.