小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

性能優(yōu)化(一)Hibernate 利用緩存(一級(jí)、二級(jí)、查詢)提高系統(tǒng)性能

 chengkunzhang 2015-11-28
      在hibernate中我們最常用的有三類緩存,分別為一級(jí)緩存、二級(jí)緩存和查詢緩存,下面我們對(duì)這三個(gè)緩存在項(xiàng)目中的使用以及優(yōu)缺點(diǎn)分析一下。

      緩存它的作用在于提高性能系統(tǒng)性能,介于應(yīng)用系統(tǒng)與數(shù)據(jù)庫之間而存在于內(nèi)存或磁盤上的數(shù)據(jù)。

      我們編程的模式一般是這樣的page-->filter-->action-->server-->dao-->db,可以在這一個(gè)請(qǐng)求過程中的任何一點(diǎn)加入緩存,上一篇介紹的是在server層加緩存:service利用aop加緩存。

       為頁面增加緩存:為頁面加緩存

      首先,來看一下一級(jí)緩存它默認(rèn)開啟且很常用。


一級(jí)緩存


    同是一種緩存常??梢杂泻脦讉€(gè)名字,這是從不同的角度考慮的結(jié)果,從緩存的生命周期角度來看一級(jí)緩存又可以叫做:sessin緩存、線程級(jí)緩存、事務(wù)級(jí)緩存。我們編程中線程、事務(wù)、session這三個(gè)概念是綁定到一起的放到了threadlocal中,同時(shí)開啟同時(shí)關(guān)閉即同生共死也有人叫做request-per-session-transaction編程;
       當(dāng)session關(guān)閉后緩存中的對(duì)象會(huì)丟失,也就是說兩個(gè)不同的session中的緩存數(shù)據(jù)都是不一樣的,緩存數(shù)據(jù)不能夠跨session訪問。

       

     緩存數(shù)據(jù)的數(shù)據(jù)類型

    在一級(jí)緩存中緩存的是實(shí)體對(duì)象,在使用查詢方法get() 、load() 、iterate()三個(gè)方法查詢時(shí)都會(huì)先查詢session緩存,如果有對(duì)象則從緩存里面取出來,如果緩存中沒有再去數(shù)據(jù)庫里面查詢。
    load()測試:測試注意一定要在同一個(gè)事務(wù)里面,當(dāng)我在Spring管理的session測試時(shí)調(diào)用兩次load()總是查詢兩次發(fā)出兩條SQL語句,還以為session級(jí)緩存沒有起作用,原來是因?yàn)閔ibernate集成spring之后事務(wù)、session都由spring管理,每次調(diào)用前后事務(wù)一級(jí)session都自動(dòng)打開和關(guān)閉,自己控制不了中間過程,于是將spring去掉拿到hibernate原session,再手動(dòng)開發(fā)關(guān)閉事務(wù)這樣做可以保證在同一個(gè)session、同一個(gè)事務(wù)里面操作方法,確實(shí)是發(fā)了一條SQL語句,看下面代碼:
    load()、get()方法:
    
  1. @Test  
  2. public void testLoad()  
  3. {  
  4.     Session session=sf.openSession();  
  5.     session.beginTransaction();  
  6.       
  7.     Category category1=(Category)session.load(Category.class,1);  
  8.     Category category2=(Category)session.load(Category.class,1);  
  9.     System.out.println(category1);  
  10.     System.out.println(category2);  
  11.       
  12.     session.getTransaction().commit();  
  13.     session.close();  
  14. }  


結(jié)果
  1. Hibernate: select category0_.id as id0_0_, category0_.name as name0_0_ from Category category0_ where category0_.id=?  
  2. hibernate.Category@10efd7c  
  3. hibernate.Category@10efd7c  


      結(jié)果不僅發(fā)送了一條語句而且兩個(gè)對(duì)象打印出來也是一樣的。
load()、get()第一次查詢時(shí)會(huì)發(fā)出sql語句,從數(shù)據(jù)庫表里面查詢;第二次查詢時(shí)會(huì)先去緩存里面查找,如果沒有發(fā)生更新修改操作,那么將從緩存中讀取數(shù)據(jù),否則查詢數(shù)據(jù)庫。
save方法
  1. @Test  
  2. public void testGet()  
  3. {  
  4.     Session session=sf.openSession();  
  5.     session.beginTransaction();  
  6.       
  7.     Category category1=new Category();  
  8.     category1.setName("新聞");  
  9.       
  10.     session.save(category1);  
  11.     Category category2=(Category)session.load(Category.class,category1.getId());  
  12.       
  13.     System.out.println(category2.getName());  
  14.     session.getTransaction().commit();  
  15.     session.close();  
  16. }  

      save也支持緩存,當(dāng)執(zhí)行save方法時(shí)首先往session緩存里面添加一條數(shù)據(jù),等事務(wù)提交或者緩存刷新時(shí)才往數(shù)據(jù)庫里面更新,從上面執(zhí)行過程可以看出只發(fā)出了一條插入語句沒有發(fā)查詢語句,因?yàn)榈诙问菑木彺嬷胁樵兂鰜淼摹?br>

      PS:save之后執(zhí)行g(shù)et或者load需要知道對(duì)象的ID,此時(shí)save方法執(zhí)行后雖然數(shù)據(jù)庫里沒有數(shù)據(jù),但是對(duì)象的ID已經(jīng)生成可以通過這個(gè)ID查詢對(duì)象。

批量插入數(shù)據(jù)

       在批量插入數(shù)據(jù)的時(shí)候采取每次插入一部分?jǐn)?shù)據(jù),如下,每次插入20條數(shù)據(jù)不需要一條一條插入。

  1. public void testInserBatch() {  
  2.     Session session = sf.openSession();  
  3.     session.beginTransaction();  
  4.       
  5.     for(int i=0; i<1000; i++) {  
  6.         Category c = new Category();  
  7.         c.setName("test" + i);  
  8.         session.save(c);  
  9.         if (i%20==0) {  
  10.             session.flush();  
  11.         }  
  12.     }  
  13.           
  14.     session.getTransaction().commit();  
  15.     session.close();  
  16. }  

每次20條數(shù)據(jù)清理一下緩存,每次清理緩存調(diào)用session.flush()方法會(huì)發(fā)出20條insert語句,但是數(shù)據(jù)庫里面還沒有數(shù)據(jù)等所有數(shù)據(jù)都發(fā)出insert語句統(tǒng)一提交事務(wù),事務(wù)同session是一個(gè)等級(jí)的因此需統(tǒng)一控制事務(wù)。


hibernate N+1問題

       Hibernate 中常會(huì)用到 set 等集合表示 1 對(duì)多的關(guān)系,在我們做的這個(gè)鐵科院項(xiàng)目中,在獲取實(shí)體的時(shí)候就能根據(jù)關(guān)系將關(guān)聯(lián)的對(duì)象或者對(duì)象集合取出,還可以設(shè)定 cacade 進(jìn)行關(guān)聯(lián)更新和刪除。這不得不說 hibernate 的 orm 做得很好,很貼近 oo 的使用習(xí)慣了。

      但是對(duì)數(shù)據(jù)庫訪問還是必須考慮性能問題的,在設(shè)定了 1 對(duì)多這種關(guān)系之后, 查詢就會(huì)出現(xiàn)傳說中的 n+1 問題。

一對(duì)多:在一方,查找得到了 n 個(gè)對(duì)象,那么又需要將 n 個(gè)對(duì)象關(guān)聯(lián)的集合取出,于是本來的一條 sql 查詢變成了 n+1 條;

多對(duì)一:在多方,查詢得到了 m 個(gè)對(duì)象,那么也會(huì)將 m 個(gè)對(duì)象對(duì)應(yīng)的 1 方的對(duì)象取出, 也變成了 m+1 ;

      解決問題的方法:

1、 使用 fetch 抓取, Hibernate 抓取策略分為單端代理和集合代理的抓取策略。

Hibernate 抓取策略 ( 單端代理的抓取策略) :

保持默認(rèn)也就是如下 :

<many-to-one name="clazz"cascade="save-update" fetch="select" />

fetch="select" 就是另外發(fā)送一條 select 語句抓取當(dāng)前對(duì)象關(guān)聯(lián)實(shí)體或者集合設(shè)置 fetch="join"

<many-to-one name="clazz"cascade="save-update" fetch="join"/>

Hibernate 會(huì)通過 select 語句使用外連接來加載器關(guān)聯(lián)實(shí)體活集合此時(shí) lazy 會(huì)失效

Hibernate 抓取策略 ( 集合代理的抓取策略 ) :

保持默認(rèn)( fetch="select" )也就是如下 :

<set name="students"inverse="true">

<key column="clazz"/>

<one-to-many class="com.june.hibernate.Student"/>

</set>

1)fetch="select" 會(huì)另外發(fā)出一條語句查詢集合

2) 設(shè)置fetch="join" 采用外連接集合的 lazy 失效

3) 這只fetch="subselect" 另外發(fā)出一條 select 語句抓取前面查詢到的所有的實(shí)體對(duì)象的關(guān)聯(lián)集合 fetch 只對(duì) HQL 查詢產(chǎn)生影響其他的則不會(huì)


OpenSessionInview問題

      這個(gè)問題出現(xiàn)是由于load()懶加載導(dǎo)致的,第一次查詢數(shù)據(jù)時(shí)使用了懶加載至查詢出來數(shù)據(jù)的ID,當(dāng)使用數(shù)據(jù)的時(shí)候還需要去數(shù)據(jù)庫里面查詢但是此時(shí)數(shù)據(jù)庫的session已經(jīng)關(guān)閉,解決此問題兩種思路一種是不使用懶加載;其二是在web層開發(fā)關(guān)閉session,延長session的生命周期。


二級(jí)緩存


    二級(jí)緩存也稱為進(jìn)程級(jí)緩存或sessionFactory緩存,也可以叫做集群范圍內(nèi)的緩存,需要第三方來實(shí)現(xiàn),hibernate默認(rèn)的二級(jí)緩存插件為ehcache這個(gè)緩存,由于二級(jí)緩存是進(jìn)程級(jí)的可能出現(xiàn)多線程并發(fā)問題,需要設(shè)置緩存的并發(fā)策略。

      hibernate二級(jí)緩存需要第三方插件支持,hibernate默認(rèn)支持為ehcache關(guān)于配置請(qǐng)參考:Spring AOP +EHcache為Service層方法增加緩存


      開啟二級(jí)緩存后對(duì)方法的影響

      get()/load()

      對(duì)于這兩個(gè)方法沒啥影響,第一次從數(shù)據(jù)庫里面查詢,第二次先判斷緩存里面有沒有數(shù)據(jù)如果沒有再去數(shù)據(jù)庫里面查詢。


查詢緩存


      查詢緩存是針對(duì)普通屬性結(jié)果集的緩存,不緩存實(shí)體對(duì)象,當(dāng)和查詢緩存關(guān)聯(lián)的表發(fā)生修改的時(shí)候,查詢緩存生命周期結(jié)束,里面的數(shù)據(jù)也隨即被清空了。

      查詢緩存的配置和使用:
List方法讀寫查詢緩存,Iterator不使用查詢緩存(查詢緩存只對(duì)query.list()有效)

      查詢緩存的配置,默認(rèn)不開啟hibernate3配置:

  1. <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>  
  2. <property name="hibernate.cache.use_second_level_cache">false</property>   
  3.      <property name="hibernate.cache.use_query_cache">true</property>    

代碼中,加上一句話 
  1. query.setCacheable(true)  

  

一級(jí)、二級(jí)、查詢之間的關(guān)系


一級(jí)緩存總是開啟狀態(tài),我們需要關(guān)注的是查詢緩存和二級(jí)緩存,查詢緩存可以只開啟一個(gè)或者兩個(gè)都打開。
開啟二級(jí)緩存時(shí),如果兩個(gè)session先后執(zhí)行l(wèi)oad或者get方法,只執(zhí)行一條語句第二次會(huì)從緩存中查找,先從一級(jí)緩存中查詢,如果沒有再去二級(jí)緩存中查找。

一級(jí)緩存同二級(jí)緩存交互

                禁止一級(jí)緩存與二級(jí)緩存交互,如下設(shè)置

session.setCacheMode(CacheMode.IGNORE);
打開一個(gè)session執(zhí)行查詢,它會(huì)先將查詢結(jié)果保存到一級(jí)緩存,待session關(guān)閉后,一級(jí)緩存中數(shù)據(jù)清空,由于禁止了一級(jí)緩存同二級(jí)緩存數(shù)據(jù)交互,因此,一級(jí)緩存關(guān)閉后不會(huì)將結(jié)構(gòu)保存到二級(jí)緩存,打開第二個(gè)session后,后再發(fā)送一條查詢語句,因此二級(jí)緩存中沒有數(shù)據(jù)。


查詢緩存與二級(jí)緩存


開啟查詢,關(guān)閉二級(jí)
         如果兩次執(zhí)行query.list(),第一次發(fā)送查詢語句會(huì)將結(jié)果對(duì)象的id保存到查詢緩存中,第二次會(huì)先從查詢緩存中取出ID,根據(jù)id先去一級(jí)緩存查找,再二級(jí)緩存,如果沒有找到會(huì)去數(shù)據(jù)庫中查找,一級(jí)緩存同session沒有關(guān)系,只和表有關(guān)系。

                開啟查詢,開啟二級(jí)緩存

兩次執(zhí)行query.list(),第一次發(fā)送查詢語句將結(jié)果


       總結(jié):

        緩存在一個(gè)項(xiàng)目中對(duì)于提高系統(tǒng)性能很重要,除了ehcache之外還有memcache、redis等緩存產(chǎn)品目前都很常用,redis具有豐富的數(shù)據(jù)類型以及單線程高效能訪問效率,memcache雖然是多線程但效率還是沒有redis高。

        這些緩存產(chǎn)品都可以實(shí)現(xiàn)分布式緩存,ehcache+rmi可以分布式緩存同步;memcache+redis都支持分布式,redis還提供了高可用性的解決方案:主從復(fù)制幾個(gè)服務(wù)器直接愛你可以切換。

        


    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多