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

  什么是二级缓存?

  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="prevalenceBase" 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="prevalenceBase" 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,以前三步配置即可实现二级缓存。

 

代码下载

 

posted @ 2010-05-19 03:46  冬子哥  阅读(5902)  评论(10编辑  收藏  举报