首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

hibernat一级缓存跟二级缓存

2012-11-08 
hibernat一级缓存和二级缓存见网址:http://www.cnblogs.com/RicCC/archive/2007/04/17/NHibernate-Entity-

hibernat一级缓存和二级缓存
见网址:http://www.cnblogs.com/RicCC/archive/2007/04/17/NHibernate-Entity-LifeCycle-Secondary-Cache-Interceptor.html
Session级别缓存(一级缓存)、SessionFactory级别缓存(二级缓存)
    一级缓存处于session级别,只能够被当前的session使用,当你的session关闭之后,这些缓存被清除掉。你对一级缓存不能进行多少控制,例如最大缓存多少个对象等。二级缓存在SessionFactory级别,这意味着从这个SessionFactory创建的所有session对象能共享这个缓存。二级缓存允许更多的控制,例如设定一个最大缓存的对象数量,以防止缓存使用过多的内存;针对每个实体可以配置缓存策略。
    NHibernate提供很多方式操纵实体和数据库,这给缓存与数据库之间的一致性带来问题,你需要了解这些问题,在程序面避免这种一致性问题发生,或者保证它是在你的控制之内。举一个例子,假如你通过session.Get()方法获取了一个对象,这时在二级缓存中该对象被缓存,然后在另外的地方有人使用Native SQL在数据库中把这条记录删除了。这种情况下,二级缓存中该对象仍然是有效的,别人在使用session.Get()获取这个对象时 NHibernate会返回二级缓存中的对象,但是在数据库中这个对象已经不存在了!

    另外是关于批量操作的问题。
    首先是批量插入、更新。一级缓存没有最大容量限制,所有persistent状态的对象都被缓存在一级缓存中,修改更新被记录下来,只在commit transaction的时候,才将更新提交数据库,在session关闭的时候清除一级缓存。假如你一次批量插入、更新10万、100万的对象,过大的缓存会导致大量的内存占用、低下的性能表现。可以使用下面的措施做一些改善:例如每500个对象执行一次应用到数据库和清除缓存的操作:
session.Flush();   //将缓存中的变化应用到数据库
session.Clear();   //清除当前session的缓存
    使用batch-size使NHibernate一次提交多个SQL语句,在性能上会有一定的改善。方法是在批量操作的对象映射配置中将batch-size设置为50、100等。
    其次是关于批量删除操作。如果你使用
int deletedRows = session.Delete("from PlantItem");
    NHibernate用下面的方式实现
IList<PlantItem> list = session.CreateQuery("from PlantItem").List<PlantItem>();
for (int i = 0; i < list.Count; i++)
{
    session.Delete(list[i]);
}
    这是因为NHibernate需要保证缓存跟数据库的一致性,上面这样的处理是跟缓存机制结合在一起的,保证了一致性(目前HB只能通过这种方式来保证),但却带来性能的损失。
    假如你一次delete的数据有几百万,就不能这样来实现。一种方式,类似上面批量插入、更新的优化手段一样来处理,你需要进一步改善一些,例如每次用 session加载1000、5000的对象(避免一次读个几百万),循环的处理。另一种方式就是使用Native SQL等,优点是速度快,但跨过了NHB的缓存机制,会导致缓存不一致。
    可以使用SessionFactory的几个方法手工清除二级缓存,可以清除某个对象实例、整个类的二级缓存对象,也可以清除collection、query的二级缓存。例如:
sessionFactory.Evict(typeof(PlantItem));  //清除二级缓存中所有PlantItem对象

    启用二级缓存的方法。首先在NHibernate的configuration里面添加缓存配置属性
<property name="cache.provider_class">
      NHibernate.Caches.Prevalence.PrevalenceCacheProvider, NHibernate.Caches.Prevalence
</property>
<property name="cache.use_query_cache">false</property>
<property name="expiration">120</property>
    然后为每个实体类选择缓存策略
<class name="PlantItem" table="TBLPLANTITEM" batch-size="10">
  <cache usage="read-write" />
    Cache provider和缓存策略参考文档进行选择。use_query_cache选项谨慎使用。
    use_query_cache启用方法:在配置节点中将cache.use_query_cache配置为true,程序代码中,使用IQuery、 ICriteria的地方调用IQuery.SetCacheable(true)或者ICriteria.SetCacheable(true),则对这些查询会启用缓存。
    如果使用NHibernate.Caches.Prevalence,可以在NHibernate的configuration里面添加一个配置项,用于设置Bamboo.Prevalence的缓存目录,如果不设置缓存目录,默认是当前应用程序目录。配置示例如下:
<property name="prevalenceBase">
      D:\Work\CMSDesign\PreTest\CMS\Web\CacheFolder
</property>
     看了下NHibernate.Caches.Prevalence源代码,请特别注意一点,NHibernate在停止NHibernate.Caches.Prevalence缓存的时候,会把这个缓存目录删除掉,因此使用NHibernate.Caches.Prevalence作为缓存时,一定要妥善的设置好缓存目录!另外,如果你用VS2005建立的是Web Site Project(Web Application Project的情况我不大清楚),调试时使用的是WebDev.WebServer.exe,在Stop的时候并不会触发 Application_End事件,因此你没有机会执行ISessionFactory.Close(),NHibernate.Caches.Prevalence的缓存目录不会被清除掉,因此下一次再执行调试而启用缓存的时候,会导致异常。有两个解决方法,一是每次手工删除缓存目录,另外一种是写一个类似exit.aspx页面,在每次退出时手工执行一次ISessionFactory.Close(),这样就会将缓存清除。

    如果使用NHibernate.Caches.SysCache,就可以象ASP.Net一样配置缓存策略,例如缓存过期时间等。还可以建立不同的 Region,使用不同的缓存策略,然后在Class映射文件的<cache usage="" region="" />中通过指定region,而使用不同的缓存策略配置。
<configuration>
    <configSections>
        <section name="syscache"
                type="NHibernate.Caches.SysCache.SysCacheSectionHandler,NHibernate.Caches.SysCache" />
    </configSections>
    <syscache>
        <cache region="foo" expiration="500" priority="4" />
        <cache region="bar" expiration="300" priority="3" />
    </syscache>
</configuration>

热点排行