Spring.NET实用技巧1——基于Prevalence下的NHibernate二级缓存使用技巧

长平狐 发布于 2012/06/11 11:54
阅读 415
收藏 0

什么是二级缓存?

NHibernate的Session提供了一级缓存。每个Session,对同一个id进行两次Load,不会发送两条SQL语句给数据库,但是Session一但关闭,一级缓存也就失效了。

  与Session相对的是,SessionFactory也提供了相应的缓存机制。

SessionFactory缓存可以依据功能和目的的不同而划分为内置缓存和外置缓存。

SessionFactory的内置缓存中存放了映射元数据和预定义SQL语句,映射元数据是映射文件中数据的副本,而预定义SQL语句是在NHibernate初始化阶段根据映射元数据推导出来的。

SessionFactory的内置缓存是只读的,应用程序不能修改缓存中的映射元数据和预定义SQL语句,

因此SessionFactory不需要进行内置缓存与映射文件的同步。SessionFactory的外置缓存是一个可配置的插件。在默认情况下,SessionFactory不会启用这个插件。外置缓存的数据是数据库数据的副本,外置缓存的介质可以是内存或者硬盘。SessionFactory的外置缓存也被称为Hibernate的二级缓存。

NHibernate的二级缓存的实现原理与一级缓存是一样的,也是通过以ID为key的Map来实现对对象的缓存。 由于NHibernate的二级缓存是作用在SessionFactory范围内的,是一种全局缓存,因而它比一级缓存的范围更广,可以被所有的Session对象所共享。


二级缓存的工作内容

       NHibernate的二级缓存同一级缓存一样,也是针对对象id来进行缓存。所以说,二级缓存的作用范围是针对根据id获得对象的查询。

       二级缓存的工作可以概括为以下几个部分:

 在执行各种条件查询时,如果所获得的结果集为实体对象的集合,那么就会把所有的数据对象根据id放入到二级缓存中。

 当NHibernate根据id访问数据对象的时候,首先会从Session一级缓存中查找,如果查不到并且配置了二级缓存,那么会从二级缓存中查找,如果还查不到,就会查询数据库,把结果按照id放入到缓存中。

 删除、更新、增加数据的时候,同时更新缓存。

 

缓存策略
只读缓存(read-only),读/写缓存(read-write),不严格的读/写缓存(nonstrict-read-write)

 

下面我就针对二级缓存的使用场景举个例子:在操作数据库的时候,常会用到事务。在使用事务begin tran而没有立刻执行commit或者rollback的时候,查询表中的数据,这时有些数据将无法获取,只有等到事务执行完毕时才会查询出这些数据。如果有长事务,甚至会出现“超时”的现象。(见下图)

换句话说,当数据库服务器遇到大并发时,没有缓存机制是很可怕的。而一级缓存仅仅只是针对Session,为了解决这类问题,则需要一种全局的缓存——二级缓存。配置了二级缓存后,查询和伴随事务的增删改操作将不受影响。

 

NHibernate的二级缓存组建有MemCache、Prevalence、SharedCache、SysCache、SysCache2、Velocity。今天主要介绍Prevalence的使用。

 

1.加入Bamboo.Prevalence.dll、Bamboo.Prevalence.Util.dll、NHibernate.Caches.Prevalence.dll这三个程序集。

下载地址 http://sourceforge.net/projects/nhcontrib/files/

 

  2.在NHibernate的映射文件加入节点<cache usage="read-write"/>的配置项。

3.配置Spring.Data.NHibernate.LocalSessionFactoryObject对象的HibernateProperties属性:

⑴.加入<entry key="cache.use_second_level_cache" value="true"/>,启用二级缓存。

⑵.加入<entry key="expiration" value="300" />,设置二级缓存的有效时间,默认情况为300秒。

⑶.加入<entry key="valenceBase" value="d:\cache" />,设置物理缓存文件的存放位置,

注意的是目前不支持相对路径,不然在开发环境会加到IDE的目录下,在部署时会加到system32/inetsrv/下。

 

 

hibernate-mapping
< hibernate-mapping  xmlns ="urn:nhibernate-mapping-2.2"  assembly ="Domain"  namespace ="Domain" >
  
< class  name ="Domain.Department, Domain"  table ="T_Department"  lazy ="true"   >
    
    
< cache  usage ="read-write"   />
    
    
< id  name ="DepartmentID"  column ="DepartmentID"  type ="Int32"   >
      
< generator  class ="native"   />
    
</ id >

    
< property  name ="Name"  type ="String" >
      
< column  name ="Name"  length ="50"  not-null ="true" ></ column >
    
</ property >


    
< bag  name ="PersonList"  inverse ="true"  lazy ="true"  generic ="true"  cascade ="all-delete-orphan"  table ="T_Person" >
      
< cache  usage ="read-write"   />
      
< key  column ="DepartmentID"  foreign-key ="FK_Person_Department" />
      
< one-to-many  class ="Domain.Person, Domain"   />
    
</ bag >

  
</ class >
</ hibernate-mapping >

 

 

 

NHibernate Configuration
   <!--  NHibernate Configuration  -->
  
< object  id ="NHibernateSessionFactory"  type ="Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate21" >
    
< property  name ="DbProvider"  ref ="DbProvider" />
    
< property  name ="MappingAssemblies" >
      
< list >
        
< value > Domain </ value >
      
</ list >
    
</ property >
    
< property  name ="HibernateProperties" >
      
< dictionary >
        
< entry  key ="hibernate.connection.provider"  value ="NHibernate.Connection.DriverConnectionProvider" />
        
< entry  key ="dialect"  value ="NHibernate.Dialect.SQLiteDialect" />
        
< entry  key ="connection.driver_class"  value ="NHibernate.Driver.SQLite20Driver" />
        
<!-- <entry key="dialect" value="NHibernate.Dialect.MsSql2005Dialect"/>
        <entry key="hibernate.connection.driver_class" value="NHibernate.Driver.SqlClientDriver"/>
-->
        
< entry  key ="use_outer_join"  value ="true" />
        
< entry  key ="show_sql"  value ="true" />
        
< entry  key ="hbm2ddl.auto"  value ="update" />
        
< entry  key ="query.substitutions"  value ="true 1, false 0, yes 'Y', no 'N'" />
        
< entry  key ="proxyfactory.factory_class"  value ="NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu" />

        
< entry  key ="cache.use_second_level_cache"  value ="true" />
        
< entry  key ="cache.default_expiration"  value ="300" />
        
< entry  key ="valenceBase"  value ="cache"   />
        
< entry  key ="expiration"  value ="300"   />
        
< entry  key ="cache.provider_class"  value ="NHibernate.Caches.Prevalence.PrevalenceCacheProvider, NHibernate.Caches.Prevalence" />
      
</ dictionary >
    
</ property >

    
<!--  provides integation with Spring's declarative transaction management features  -->
    
< property  name ="ExposeTransactionAwareSessionFactory"  value ="true"   />


  
</ object >

 

 

 

OK,以前三步配置即可实现二级缓存。

 

代码下载

 


原文链接:http://www.cnblogs.com/GoodHelper/archive/2010/05/19/SpringNet_NHbernate_Prevalence.html
加载中
返回顶部
顶部