对hibernate的二级缓存的理解

来源:互联网 发布:购买软件会计分录 编辑:程序博客网 时间:2024/04/29 06:35
于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_.*** as ***0_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_.*** as ***0_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_.*** as ***0_0_ from test.t_user tuser0_ where tuser0_.id=?
Hibernate: select tuser0_.id as id0_0_, tuser0_.name as name0_0_, tuser0_.*** as ***0_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_.*** as ***0_ 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支持事存.
 
Hibernate据的方式有不同的几,其与缓合使用的效果也不相同,而Hibernate中具体怎么使用存其是我心的一个问题,直接涉及到性能方面。
存在Hibernate中主要有三方面:一级缓存、二级缓存和查询缓存;一级缓存在Hibernate中对应的即session存,也就是 session关闭时缓存即被除,一级缓存在Hibernate中是不可配置的部分;二级缓存在Hibernate中对应的即 SessionFactory存,通常来讲SessionFactory的生命周期和用的生命周期相同,所以可以看成是存或集群存,二级缓存在Hibernate中是可以配置的,可以通class-cache配置粒度级别存(class-cache在class中生任何化的情下自更新),同也可通collection-cache配置集合粒度级别存(collection-cache在 collection中增加了元素或者除了元素的情下才自更新,也就是collection中元素化的情是不更新的),存自然会带来并发访问问题这个时候相的就要根据来设存所采用的事隔离级别,和的事隔离级别概念基本一多介的, ^_^;查询缓存在Hibernate同是可配置的,默关闭的,可以通过设置cache.use_ query_cachetrue开查询缓存。根据存的通常实现策略,我可以理解Hibernate的种缓存,存的实现是通key/value的Map方式来实现,在 Hibernate的一、二查询缓存也同如此,一、二级缓存使用的key均po的主ID,value即po象,查询缓存使用的则为查询件、查询参数查询页数,value有两种,如果采用的是select po.property这样的方式那value个结果集,如采用的是from这样的方式那value为获取的果集中各po象的主ID这样的作用很明存,^_^
简单完Hibernate的存后,再合Hibernate的据方式来说存的具体使用方式,在Hibernate中据常用的方式主要有四:Session.load、Session.get、Query.list、Query.iterator。
1、Session.load
      在
行session.load,Hibernate首先从当前session的一级缓存中取id对应,在取不到的情下,根据该对象是否配置了二级缓做相理,如配置了二级缓存,则从级缓存中取id对应,如仍然取不到则还需要根据是否配置了延载来决定如何行,如未配置延载则从数中直接取,在从数库获取到据的情下,Hibernate充一级缓存和二级缓存,如配置了延载则直接返回一代理,只有在触发代理库查询的操作。
      在
这样的情下我就可以看到,在session一直打的情下,要注意在适级缓行刷新操作,通常是在该对象具有关联维护候,在Hibernate中可以使用象session.clear、session.evict的方式强制刷新一级缓存。
      二
级缓生任何化(新增、更新、除)的情下都的被更新。
2、Session.get
      在
行Session.get,和Session.load不同的就是在当从缓存中取不到,直接从数取id对应
3、Query.list
      在
行Query.list,Hibernate的做法是首先检查是否配置了查询缓存,如配置了则从查询缓存中找key为查询语句+查询参数+页条件的,如取不到则从数取,从数库获取到后Hibernate将会充一、二查询缓存,如取到的直接的果集,直接返回,如取到的一堆id的再根据id取相(Session.load),最后形成果集返回,可以看到,在这样的情下,list也是有可能造成N次的查询的。
     
查询缓存在生任何化的情下都被自空。
4、Query.iterator
      在
行Query.iterator,和Query.list的不同的在于从数库获取的理上,Query.iterator向库发起的是 select id from这样句,也就是是先取符合查询条件的id,之后在行iterator.next才再次起session.load的实际据。
      可
,在有二级缓查询参数的情下,Query.iterator比Query.list更高效。

种获据的方式都各有适用的合,要根据实际做相定,^_^,最好的方式无疑就是打show_sql选项看看行的情况来做分析,系统结构上只用保证这种调整是容易实现的就好了,在cache这个方面的整自然是非常的容易,只需要整配置文件里的置,而查询的方式外部蔽,这样要根据实际况调整也非常容易。
1<hibernate-configuration>
 
    <session-factory>
       <propertyname="connection.username">sa</property>
       <propertyname="connection.url">
           jdbc:microsoft:sqlserver://localhost:1433;databasename=pubs
       </property>
       <propertyname="dialect">
           org.hibernate.dialect.SQLServerDialect
       </property>
       <propertyname="myeclipse.connection.profile">conn</property>
       <propertyname="connection.driver_class">
           com.microsoft.jdbc.sqlserver.SQLServerDriver
       </property>
       <propertyname="show_sql">true</property>
       <!--添加2级缓存开始 -->
       <propertyname="cache.provider_class">
           org.hibernate.cache.EhCacheProvider
       </property>
       <propertyname="hibernate.cache.use_query_cache">true</property>
       <!--结束 -->
       <mappingresource="org/jw/po/Users.hbm.xml"/>
 
    </session-factory>
 
</hibernate-configuration>
2
<hibernate-mapping>
    <classname="org.jw.po.Users"table="users"schema="dbo"catalog="pubs">
        <!--配置-->
        <cacheusage="read-only"></cache>
        <idname="sid"type="java.lang.Integer">
            <columnname="sid"/>
            <generatorclass="identity"/>
        </id>
        <propertyname="sname"type="java.lang.String">
            <columnname="sname"length="20"not-null="true"/>
        </property>
    </class>
</hibernate-mapping>