風雨無阻

          hibernate二級緩存的實現

          于Hibernate這類ORM而言,的尤重要,是持久性能提升的關鍵.簡單來講Hibernate就是JDBC行封裝,以實現內狀態的管理,OR系的映射等,但帶來的就是訪問效率的降低,和性能的下降,而存就是彌補這一缺點的重要方法.

              
          存就是庫數據在存中的臨時容器,包括庫數據在存中的臨時,位于庫與數庫訪問層.ORM查詢數首先根據自身的存管理策略,在存中找相關數據,如發現所需的據,直接據作為結果加以利用,而避免了庫調用性能的開銷.而相對內存操作而言,庫調用是一代價高程.

              一般
          來講ORM中的存分以下幾:

                  1.
          務級緩存:即在前事圍內存.就Hibernate來講,務級緩存是基于Session的生命周期實現的,每Session存在一個數存,它隨著Session的建而存在,著Session的毀而亡,因此也稱為Session Level Cache.

                  2.
          級緩存:即在某個應用中或用中某個獨庫訪問子集中的共享存,此存可由多共享(用事),存共享策略與應用的事隔離機制密切相.在Hibernate中,級緩存由SessionFactory實現,所有由一SessionFactory建的Session例共享此存,因此也稱為SessionFactory Level Cache.

                  3.
          分布式存:即在多個應例,多JVM共享的存策略.分布式存由多個應級緩成,通種遠程機制(RMI,JMS)實現個緩據同步,任何一個實例的據修改,將導致整集群狀態同步.

              Hibernate
          存:

                  1.
          存(Session Level Cache也級緩存):

                  
          明:

          java 代

          public class Test {    
            
                public void get(){    
            
                      Session session = HibernateSessionFactory.getSession();    
                      TUser t = (TUser)session.get("hibernate.TUser", 2);    
                      System.out.println(t.getName());    
                      session.close();    
                      }    
            
          }    
            

                      
          測試:在控制臺打印出一SQL句:Hibernate: select tuser0_.id as id0_0_, tuser0_.name as name0_0_, tuser0_.sex as sex0_0_ from test.t_user tuser0_ where tuser0_.id=? 行了一次調用.

                代
          更改如下:

          public class Test {    
              
                public void get(){    
            
                      Session session = HibernateSessionFactory.getSession();    
                      TUser t = (TUser)session.get("hibernate.TUser", 2);    
                      System.out.println(t.getName());    
                      TUser tt = (TUser)session.get("hibernate.TUser", 2);    
                      System.out.println(tt.getName());    
                      session.close();    
            
                }    
            
          }    
            

                 再
          測試:行了查詢,控制臺仍然只打出一SQL句:Hibernate: select tuser0_.id as id0_0_, tuser0_.name as name0_0_, tuser0_.sex as sex0_0_ from test.t_user tuser0_ where tuser0_.id=?  是只行了一次調用.

                 再
          更改如下:

          public class Test {    
              
                public void get(){    
            
                      Session session = HibernateSessionFactory.getSession();    
                      TUser t = (TUser)session.get("hibernate.TUser", 2);    
                      System.out.println(t.getName());    
                      session.close();    
                      Session session1 = HibernateSessionFactory.getSession();    
                      TUser tt = (TUser)session1.get("hibernate.TUser", 2);    
                      System.out.println(tt.getName());    
                      session1.close();    
            
                }    
            
          }    

                
          繼續測試:查詢控制臺打印兩條SQL句:Hibernate: select tuser0_.id as id0_0_, tuser0_.name as name0_0_, tuser0_.sex as sex0_0_ from test.t_user tuser0_ where tuser0_.id=?
          Hibernate: select tuser0_.id as id0_0_, tuser0_.name as name0_0_, tuser0_.sex as sex0_0_ from test.t_user tuser0_ where tuser0_.id=?

                
          結論:Hibernate查詢時總是先在存中查詢,存中有所需據才查詢.Hibernate存是基于Session的生命周期的,也就是存在于每Session部,它隨著Session的建而存在,著Session的毀而亡,存一般由Hibernate自動維護,不需要人,然我也可以根據需要行相操作:Session.evict(Object)(指定從內除),Session.clear()(存).(如在查詢間加入Session.clear()將會清存,使得一Sesion部的次相同的查詢對數庫進次操作).

                2.二
          級緩存:(有時稱為SessionFactory Level Cache)

                Hibernate
          本身未提供二級緩存的品化實現(只提供了一基于HashTable的簡單緩存以供調試),里我使用的是第三方件:EHcache.Hibernate的二級緩實現需要行以下配置(Hibernate3):

                首先在hibernate.cfg.xml
          添加:



          <property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>  
          <property name="hibernate.cache.use_query_cache">true</property>  

          然后在映射文件中添加:
          <cache usage="read-only"/>  

                      
          測試上面代:控制臺出多了這樣一句[ WARN] (CacheFactory.java:43) - read-only cache configured for mutable class: hibernate.TUser,二級緩用成功!!      

          java 代

          public class Test {    
              
                public void executeQuery(){    
                
                      List list = new ArrayList();    
                      Session session = HibernateSessionFactory.getSession();    
                      Query query = session.createQuery("from TUser t");    
                      query.setCacheable(true);//
          激活查詢緩存    
                      list = query.list();    
                      session.close();    
            
                }    
                public void get(){    
            
                      Session session = HibernateSessionFactory.getSession();    
                      TUser t = (TUser)session.get("hibernate.TUser", 2);    
                      System.out.println(t.getName());    
                      session.close();    
            
               }    
            
          }    

                
          測試:控制臺只出一SQL句:Hibernate: select tuser0_.id as id0_, tuser0_.name as name0_, tuser0_.sex as sex0_ from test.t_user tuser0_(即Query query = session.createQuery("from TUser t")句代對應的SQL).  executeQuery()方法get()方法使用的是不同的Session!!可是executeQuery()方法get()方法只對數庫進行了一次操作,就是二級緩存在起作用了.  

                
          結論:Hibernate級緩存是SessionFactory存,Session共享,使用需要使用第三方的件,新版HibernateEHcache的二級緩實現.

                
          存同步策略:存同步策略定了象在存中的存取規則,須為個實指定相存同步策略.Hibernate中提供了4不同的存同步策略:(暫時記個概)

                1.read-only:
          .于不會發生改據可使用(對數據只能查詢,其他的增刪改都會報錯不關是1或2緩存中.

                2.nonstrict-read-write:
          如果程序對并發訪問下的據同步要求不格,且據更新低,采用本存同步策略可好性能.(不能在二級緩存進行增刪改都會報錯)

                3.read-write:
          格的讀寫緩存.基于時間戳判定機制,實現了"read committed"事隔離等.用于對數據同步要求的情,但不支持分布式存,實際應用中使用最多的存同步策略.(都可以比較常用的)

                4.transactional:
          存,必須運行在JTA事務環境中.此存中,存的相操作被添加到事中(此似于一個內),如事,則緩沖池的一同回到事始之前的狀態.實現了"Repeatable read"事隔離等,有效保據的合法性,適對關鍵數據的存,Hibernate存中,只有JBossCache支持事存.


          create table teamEH (id varchar(32),teamname varchar(32));

          create table studentEH (id varchar(32),name varchar(32),team_id varchar(32));

          POJO:

           

          package EHCache;

          public class Student ...{

              private String id; //標識id

              private String name; //學生姓名

              private Team team;//班級

              public String getName() ...{

                  return name;

              }

             

              public void setId(String id) ...{

                  this.id = id;

              }

             

              public void setName(String stuName) ...{

                  this.name = stuName;

              }

            

              public String getId() ...{

                  return id;

              }

              public Student() ...{ //無參的構造函數

              }

             

              public Team getTeam() ...{

                  return team;

              }

              public void setTeam(Team team) ...{

                  this.team = team;

              }

          }

          package EHCache;

          import java.util.HashSet;

          import java.util.Set;

          public class Team ...{

              private String id;

              private Set students;

              private String teamName;

              public String getId() ...{

                  return id;

              }

              public void setId(String id) ...{

                  this.id = id;

              }

              public String getTeamName() ...{

                  return teamName;

              }

              public void setTeamName(String name) ...{

                  this.teamName = name;

              }

              public Set getStudents() ...{

                  return students;

              }

              public void setStudents(Set students) ...{

                  this.students = students;

              }

          }

           Team.hbm.xml

          其中<cache>標簽表示對student集合緩存,但只緩存id,如果需要緩存student實例,則需要在student.hbm.xml中的

          class標簽中配置<cache>

           

          <?xml version="1.0" encoding="utf-8"?>

          <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

          "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

          <!-- 

              Mapping file autogenerated by MyEclipse - Hibernate Tools

          -->

          <hibernate-mapping package="EHCache" >

              <class name="EHCache.Team" table="teamEH" lazy="false">

                 <id name="id" column="id">

                   <generator class="uuid.hex"></generator>

                 </id>

                 <property name="teamName" column="teamName"></property>

                 

                 <set name="students" 

                      lazy="true" 

                      inverse="true" 

                      outer-join="false"

                      batch-size="2"

                      cascade="save-update"

                     >

                     <!-- 對students集合緩存,但只是緩存student-id如果要對整個對象緩存,

                          還需要在Student.hbm.xml的class標簽中加入<cache>標簽 -->

                   <cache usage="read-write"/>

                   <key column="team_id"></key>

                   <one-to-many class="EHCache.Student"/>

                 </set>

                </class>

          </hibernate-mapping>

           

          Student.hbm.xml

           

          <?xml version="1.0" encoding="utf-8"?>

          <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

          "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

          <!-- 

              Mapping file autogenerated by MyEclipse - Hibernate Tools

          -->

          <hibernate-mapping package="EHCache" >

             

              <class name="EHCache.Student" table="studentEH" lazy="false">

                 <cache usage="read-write"/>

                 <id name="id" column="id" unsaved-value="null">

                   <generator class="uuid.hex"></generator>

                 </id>

                 <property name="name" column="name"></property>

              

                 <many-to-one name="team" 

                              column="team_id"

                              outer-join="true" 

                              cascade="save-update"

                              class="EHCache.Team"></many-to-one>

                </class>

          </hibernate-mapping>

           

          Hibernate.cfg.xml

          配置hibernate.cache.provider_class以啟用EHCache

          <?xml version='1.0' encoding='UTF-8'?>

          <!DOCTYPE hibernate-configuration PUBLIC

                    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"

                    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

          <!-- Generated by MyEclipse Hibernate Tools.                   -->

          <hibernate-configuration>

          <session-factory>

              <property name="connection.username">root</property>

              <property name="connection.url">

                  jdbc:mysql://localhost:3306/schoolproject?characterEncoding=gb2312&amp;useUnicode=true

              </property>

              <property name="dialect">

                  org.hibernate.dialect.MySQLDialect

              </property>

              <property name="myeclipse.connection.profile">mysql</property>

              <property name="connection.password">1234</property>

              <property name="connection.driver_class">

                  com.mysql.jdbc.Driver

              </property>

              <property name="hibernate.dialect">

                  org.hibernate.dialect.MySQLDialect

              </property>

              <property name="hibernate.show_sql">true</property>

              <property name="current_session_context_class">thread</property>

              <property name="hibernate.cache.provider_class">

                      org.hibernate.cache.EhCacheProvider

                  </property>

              <mapping resource="EHCache/Student.hbm.xml" />

              <mapping resource="EHCache/Team.hbm.xml" />

          </session-factory>

          </hibernate-configuration>

          EHCache.xml(放在classpath下)

           

          <ehcache>

           

              <diskStore path="c:\cache"/>  <!--緩存文件存放位置-->

              <defaultCache

                  maxElementsInMemory="10000"

                  eternal="false"

                  timeToIdleSeconds="120"

                  timeToLiveSeconds="120"

                  overflowToDisk="true"

                  />

              <cache name="EHCache.Student"

                  maxElementsInMemory="500"    <!---超過500實例,就將多出的部分放置緩存文件中->

                  eternal="false"

                  timeToIdleSeconds="120"

                  timeToLiveSeconds="120"

                  overflowToDisk="true"

                  /> -->

              <!-- Place configuration for your caches following -->

          </ehcache>

           

          測試代碼(插入準備數據部分)

           

          package EHCache;

          import java.io.File;

          import java.util.List;

          import org.hibernate.Session;

          import org.hibernate.SessionFactory;

          import org.hibernate.Transaction;

          import org.hibernate.cfg.Configuration;

          public class Test ...{

              public static void main(String[] args) ...{

                  String filePath=System.getProperty("user.dir")+File.separator+"src/EHCache"+File.separator+"hibernate.cfg.xml";

                  File file=new File(filePath);

                  SessionFactory sessionFactory=new Configuration().configure(file).buildSessionFactory();

                  Session session=sessionFactory.openSession();

                  Transaction tx=session.beginTransaction();

                  

          //        Team team=new Team();

          //        team.setTeamName("team1");

          //        

          //        

          //        for(int i=0;i<1000;i++){

          //            Student stu=new Student();

          //            stu.setName("tom"+i);

          //            stu.setTeam(team);

          //            session.save(stu);

          //        }

          //        tx.commit();

          //        

              }

          }

           

          測試成功后,運行以下代碼

           

          package EHCache;

          import java.io.File;

          import java.util.List;

          import org.hibernate.Session;

          import org.hibernate.SessionFactory;

          import org.hibernate.Transaction;

          import org.hibernate.cfg.Configuration;

          public class Test ...{

              public static void main(String[] args) ...{

                  String filePath=System.getProperty("user.dir")+File.separator+"src/EHCache"+File.separator+"hibernate.cfg.xml";

                  File file=new File(filePath);

                  SessionFactory sessionFactory=new Configuration().configure(file).buildSessionFactory();

                  Session session=sessionFactory.openSession();

                  Transaction tx=session.beginTransaction();

                  

              

                  //模擬多用戶訪問數據

                  Session session1=sessionFactory.openSession();

                  Transaction tx1=session1.beginTransaction();

                  List list=session1.createQuery("from Student").list();

                  for(int i=0;i<list.size();i++)...{

                      Student stu=(Student)list.get(i);

                      System.out.println(stu.getName());

                  }

                  tx1.commit();

                  session1.close();    

              

                  Session session2=sessionFactory.openSession();

                  Transaction tx2=session2.beginTransaction();

                      //這個uuid從剛才插入的數據中復制一個student的id

                  Student stu=(Student)session2.get(Student.class, "4028818316d184820116d184900e0001");

                  System.out.println(stu.getName());

                  tx2.commit();

                  session2.close();

              }

          }

           

          結果如下:

          log4j:WARN No appenders could be found for logger (org.hibernate.cfg.Environment).

          log4j:WARN Please initialize the log4j system properly.

          Hibernate: select student0_.id as id0_, student0_.name as name0_, student0_.team_id as team3_0_ from studentEH student0_

          Hibernate: select team0_.id as id1_0_, team0_.teamName as teamName1_0_ from teamEH team0_ where team0_.id=?

          tom0

          tom1

          tom2

          tom3

          tom4

          tom5

          tom6

          tom7

          tom8

          tom9

          tom10

          ........................................

          tom974

          tom975

          tom976

          tom977

          tom978

          tom998

          tom999

          Hibernate: select team0_.id as id1_0_, team0_.teamName as teamName1_0_ from teamEH team0_ where team0_.id=?

          tom0

           

          可以看到,第二次查詢,已經不再訪問數據庫了,而且,查看c:\cache文件夾,也可以看到,數據已經緩存成功了

          posted on 2008-04-16 18:17 秋楓故事 閱讀(1762) 評論(1)  編輯  收藏

          評論

          # re: hibernate二級緩存的實現 2009-09-15 17:56 jack.lxh@gmail.com

          您好文章中的說明 的hiberate 一級緩存與二級緩存的交互,我之前就知道,但是如果在一個web應用中 這個進程級別與 application 范圍有什么區別  回復  更多評論   


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          <2008年4月>
          303112345
          6789101112
          13141516171819
          20212223242526
          27282930123
          45678910

          導航

          統計

          常用鏈接

          留言簿(2)

          隨筆分類

          隨筆檔案

          新聞檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 平乐县| 大足县| 延长县| 株洲县| 通许县| 万载县| 甘德县| 富阳市| 威信县| 民丰县| 高碑店市| 梁河县| 正宁县| 晋州市| 巴楚县| 称多县| 兴业县| 大英县| 崇阳县| 广州市| 池州市| 滦平县| 南开区| 荥经县| 祁门县| 杨浦区| 改则县| 昭觉县| 察哈| 乌恰县| 巴彦淖尔市| 三门峡市| 任丘市| 皮山县| 沽源县| 鄂尔多斯市| 梁河县| 疏勒县| 民勤县| 化隆| 佛学|