Java学习之道: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_.*** 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 共享,使用 需要使用第三方的 件,新版Hibernate EHcache 的二 级缓 实现 .

      
存同步策略: 存同步策略 定了 象在 存中的存取 规则 , 须为 个实 指定相 存同步策略.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_cache true 开查询缓 存。根据 存的通常 实现 策略,我 可以 理解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 >
        < property  name = "connection.username" > sa </ property >
        < property  name = "connection.url" >
           jdbc:microsoft:sqlserver://localhost:1433;databasename=pubs
        </ property >
        < property  name = "dialect" >
           org.hibernate.dialect.SQLServerDialect
        </ property >
        < property  name = "myeclipse.connection.profile" > conn </ property >
        < property  name = "connection.driver_class" >
           com.microsoft.jdbc.sqlserver.SQLServerDriver
        </ property >
        < property  name = "show_sql" > true </ property >
        <!--  添加 2 级缓存开始  -->
        < property  name = "cache.provider_class" >
           org.hibernate.cache.EhCacheProvider
        </ property >
        < property  name = "hibernate.cache.use_query_cache" > true </ property >
        <!--  结束  -->
        < mapping  resource = "org/jw/po/Users.hbm.xml"  />
 
     </ session-factory >
 
</ hibernate-configuration >
2
< hibernate-mapping >
     < class  name = "org.jw.po.Users"  table = "users"  schema = "dbo"  catalog = "pubs" >
         <!-- 配置 -->
         < cache  usage = "read-only" ></ cache >
         < id  name = "sid"  type = "java.lang.Integer" >
             < column  name = "sid"  />
             < generator  class = "identity"  />
         </ id >
         < property  name = "sname"  type = "java.lang.String" >
             < column  name = "sname"  length = "20"  not-null = "true"  />
         </ property >
     </ class >
</ hibernate-mapping >
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值