本节内容

  • 引入
  • 介绍NHibernate二级缓存
  • NHibernate二级缓存提供程序
  • 实现NHibernate二级缓存
  • 结语

引入

上一篇我介绍了NHibernate内置的一级缓存即ISession缓存。这篇我们来了解下NHibernate二级缓存即ISessionFactory级别缓存。二级缓存是可扩展的,在NHibernate  Contrib上提供了第三方NHibernate二级缓存提供程序。

介绍NHibernate二级缓存

NHibernate二级缓存由ISessionFactory创建,可以被所有的ISession共享。

在NHibernate中,当我们启用NHibernate二级缓存。使用ISession进行数据操作时,NHibernate首先从内置缓存(一级缓存)中查找是否存在需要的数据,如果内置缓存不存在需要的数据,则查询二级缓存,如果二级缓存中存在所需数据,则直接使用缓存中数据,否则从数据库中查询数据并放入缓存中。

NHibernate本身提供了一个基于Hashtable的HashtableCache缓存,但是功能非常有限而且性能比较差,不适合在大型应用程序使用,我们可以使用第三方缓存提供程序作为NHibernate二级缓存实现。

但是,使用缓存的缺点就是如果缓存策略设置不当,NHibernate不知道其它应用程序对数据库的修改及时更新缓存。因此,建议只对系统经常使用、数据量不大且不会被其它应用程序修改的只读数据(或很少被修改的数据)使用缓存。

NHibernate二级缓存提供程序

NHibernate提供了NHibernate.Cache.ICacheProvider接口用来支持第三方缓存提供程序实现。开发缓存提供程序时,需要实现该接口作为NHibernate和缓存实现直接的适配器。NHibernate提供了常见的缓存提供程序的内置适配器,这些适配器都实现了NHibernate.Cache.ICacheProvider接口。

除了NHibernate本身提供的一个基于Hashtable的HashtableCache缓存,在NHibernate  Contrib上提供了六种第三方NHibernate二级缓存提供程序,完全开源的。我们直接下载其程序集引用到我们的项目中就可以使用了。

  • NHibernate.Caches.MemCache
  • NHibernate.Caches.Prevalence
  • NHibernate.Caches.SharedCache
  • NHibernate.Caches.SysCache
  • NHibernate.Caches.SysCache2
  • NHibernate.Caches.Velocity

实现NHibernate二级缓存

NHibernate二级缓存是一个可插拔的组件。在默认情况下,NHibernate不启动二级缓存。如果要使用二级缓存则需要在NHibernate配置文件中显式的启用二级缓存。NHibernate二级缓存可以分别为每一个具体的类和集合配置应用级或分布式缓存。

缓存并发策略

提示一下,在NHibernate官方文档中有介绍,详情请参考NHibernate官方文档。当两个独立的事务同时访问数据库时,可能产生丢失更新、不可重复读等并发问题。同样,当两个并发事务同时访问缓存时,也有可能产生各种并发问题。因此,在缓存级别也需要设置相应的并发访问策略。

NHibernate内置四种并发访问策略:

  • read-only:只读缓存。适用于只读数据。可用于群集中。
  • read-write:读写缓存。
  • nonstrict-read-write:非严格读写缓存。不保证缓存与数据库的一致性。
  • transactional:事务缓存。提供可重复读的事务隔离级别。

我们动手实现二级缓存吧~~~

Step1:配置第三方缓存提供程序

我们在NHibernate配置文件中通过cache.provider_class属性显式指定缓存实现,属性值为缓存适配器的具体类名。如果你使用上面的第三方缓存提供程序,还需要配置缓存提供程序本身。这里我设置NHibernate本身提供了一个基于Hashtable的HashtableCache缓存。

<property name="cache.provider_class">NHibernate.Cache.HashtableCacheProvider</property>

Step2:显式启用二级缓存

在NHibernate配置文件中使用cache.use_second_level_cache属性显式启用二级缓存,参数为Bool值,这里启用设置为true。

<property name ="cache.use_second_level_cache">true</property>

Step3:配置第三方缓存提供程序本身

如果你使用第三方缓存提供程序,那么需要对第三方缓存提供程序本身进行配置,需要详细配置第三方缓存提供程序缓存属性:保存时间、过期时间、可以缓存对象数量。这里我就使用NHibernate本身提供的HashtableCache缓存,所以这一步就省略了。

Step4:为每一个持久化类和集合指定相应的缓存策略

方法一:在映射文件中通过<cache>元素配置类和集合的缓存策略,在Class元素或者集合元素中添加<cache>元素进行配置。注意:<cache>元素必须在<id>元素之前。

<cache usage="read-only|read-write|nonstrict-read-write" region="默认类或集合名称"/>

方法二:在NHibernate配置文件hibernate.cfg.xml中通过<class-cache>元素和<collection-cache>元素分别配置类和集合的缓存策略。

我还是建议大家使用NHibernate配置文件定义缓存策略,这样可以避免在各个映射文件配置缓存定义而增大维护难度。

指定类:

<class-cache class="类名称" region="默认类名称" include="all|non-lazy"
usage="read-only|read-write|nonstrict-read-write|transactional" />

指定集合:

<collection-cache collection ="集合名称" region="默认集合名称"
usage="read-only|read-write|nonstrict-read-write|transactional"/>

具体意义是:

  • region:可选,默认值为类或集合的名称,用来指定二级缓存的区域名,对应于缓存实现的一个命名缓存区域。
  • include:可选,默认值为all,当取non-lazy时设置延迟加载的持久化实例的属性不被缓存。
  • usage:声明缓存同步策略,就是上面说明的四种缓存策略。

配置文件和映射文件定义不一样,不知道是不是BUG。

Step5:开始测试

在测试之前,我们先看看上面的步骤我们完成了哪些内容。我贴出具体代码:

代码片段1:NHibernate配置文件:

<?xml version="1.0" encoding="utf-8"?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2" >
<session-factory name="NHibernateSample.DAL.Test">
<!--
配置二级缓存实例文件
作者:李永京(YJingLee's Blog)
出处:http://lyj.cnblogs.com
-->
<property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
<property name="connection.connection_string">
Data Source=.\SQLEXPRESS;Initial Catalog=NHibernateSample;
Integrated Security=True;Pooling=False</property>
<property name="adonet.batch_size">10</property>
<property name="show_sql">true</property>
<property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
<property name="use_outer_join">true</property>
<property name="query.substitutions">true 1, false 0, yes 'Y', no 'N'</property>
<!--1.配置二级缓存提供程序-->
<property name="cache.provider_class">NHibernate.Cache.HashtableCacheProvider</property>
<!--2.显式启用二级缓存-->
<property name ="cache.use_second_level_cache">true</property>
<!--4.启动查询缓存(注:下一篇内容:http://lyj.cnblogs.com)-->
<property name="cache.use_query_cache">true</property>
<mapping assembly="DomainModel"/>
<!--3.配置映射的二级缓存-->
<class-cache class="DomainModel.Entities.Customer,DomainModel" usage="read-write"/>
</session-factory>
</hibernate-configuration>

代码片段2:Customer.hbm.xml映射文件:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="DomainModel" namespace="DomainModel">
<!--
配置二级缓存映射文件
作者:李永京(YJingLee's Blog)
出处:http://lyj.cnblogs.com
-->
<class name ="DomainModel.Entities.Customer,DomainModel"
table="Customer">
<cache usage="read-write"/>
<id name="CustomerId" type="Int32" unsaved-value="0">
<generator class ="native"></generator>
</id>
<version name="Version" type="integer" unsaved-value="0"/>
<component name="Name" class="DomainModel.Entities.Name,DomainModel">
<property name="Firstname"/>
<property name ="Lastname"/>
</component>
<set name="Orders" table="`Order`" generic="true" inverse="true">
<cache usage="read-only"/>
<key column="Customer" foreign-key="FK_CustomerOrders"/>
<one-to-many class="DomainModel.Entities.Order,DomainModel"/>
</set>
</class>
</hibernate-mapping>

Step6:测试代码

在不同Session中获取实体:

[Test]
public void SessionFactoryCacheTest()
{
using (_session)
{
Console.WriteLine("--Session 1--读取持久化实例--");
Customer customer1 = _session.Get<Customer>(1);
Assert.IsNotNull(customer1);
}
ResetSession();
using (_session)
{
Console.WriteLine("--Session 2--读取持久化实例--");
Customer customer2 = _session.Get<Customer>(1);
Assert.IsNotNull(customer2);
}
}

分析一下:在第一次查询数据时,由于一级、二级缓存中都不存在需要的数据,这时NHibernate从数据库中查询数据。第二次读取同一数据,NHibernate首先从内置缓存(一级缓存)中查找是否存在所需要数据,由于不是在同一个ISession中,所以内置ISession缓存中不存在所需数据,NHibernate则查询二级缓存,这时由于第一次查询了这条数据,所以在二级缓存中存在所需数据,则直接使用缓存中数据。看看输出结果吧:

结语

好了,这篇就到这里吧!我们初步认识了NHibernate二级缓存,并用一个查询例子说明了一切,但是关于二级缓存还有很多内容,比如你修改、删除数据时,二级缓存是什么策略呢?我们如果使用查询缓存呢?如何管理NHibernate二级缓存呢?这就在下一篇揭晓吧

NHibernate教程(20)——二级缓存(上)的更多相关文章

  1. NHibernate教程(21)——二级缓存(下)

    本节内容 引入 使用NHibernate二级缓存 启用缓存查询 管理NHibernate二级缓存 结语 引入 这篇我还继续上一篇的话题聊聊NHibernate二级缓存剩下的内容,比如你修改.删除数据时 ...

  2. NHibernate系列文章九:NHibernate对象二级缓存上

    摘要 NHibernate的二级缓存由SessionFactory管理,由所有Session共享. NHibernate缓存读取顺序: 首先从一级缓存中读取,如果一级缓存对象存在,则读取一级缓存对象并 ...

  3. NHibernate教程(19) —— 一级缓存

    本节内容 引入 NHibernate一级缓存介绍 NHibernate一级缓存管理 结语 引入 大家看看上一篇了吗?对象状态.这很容易延伸到NHibernate的缓存.在项目中我们灵活的使用NHibe ...

  4. NHibernate使用MemCache二级缓存

    首先,当然是安装MemCache服务器端了. 然后配置过程,仅仅两个问题. 1.NHibernate要与NHibernate.Cache的版本要一致.否则,NHibernate.Caches.MemC ...

  5. [Nhibernate]二级缓存(二)

    目录 写在前面 文档与系列文章 更新数据 二级缓存管理 总结 写在前面 本篇文章也算nhibernate入门系列的结尾了,在总结nhibernate系列的过程中,遇到了很多问题,学习的过程也是解决bu ...

  6. [Nhibernate]二级缓存

    [Nhibernate]二级缓存 目录 写在前面 文档与系列文章 二级缓存 Nhibernate二级缓存提供程序 一个例子 总结 写在前面 上篇文章介绍了nhibernate中一级缓存的相关内容,一级 ...

  7. [Nhibernate]二级缓存(一)

    目录 写在前面 文档与系列文章 二级缓存 Nhibernate二级缓存提供程序 一个例子 总结 写在前面 上篇文章介绍了nhibernate中一级缓存的相关内容,一级缓存过期时间和ISession对象 ...

  8. NHibernate系列文章十:NHibernate对象二级缓存下

    摘要 上一节对NHibernate二级缓存做了简单介绍,NHibernate二级缓存是由SessionFactory管理的,所有Session共享.这一节介绍二级缓存其他两个方面:二级缓存查询和二级缓 ...

  9. 基于NHibernate二级缓存的MongoDB组件

    设计一套基于NHibernate二级缓存的MongoDB组件(上)   摘要:NHibernate Contrib 支持很多第三方的二级缓存,如SysCache,MemCache,Prevalence ...

随机推荐

  1. CSS样式----浮动(图文详解)

    标准文档流 宏观地讲,我们的web页面和photoshop等设计软件有本质的区别:web页面的制作,是个"流",必须从上而下,像"织毛衣".而设计软件,想往哪里 ...

  2. HPU--1091 N!的位数

    1091: N!的位数 [数学] 时间限制: 1 Sec 内存限制: 128 MB提交: 97 解决: 12 统计 题目描述 我们知道n!=n*(n-1)*(n-2)*-*2*1. 那么给定一个n,n ...

  3. Linux 粘着位(sticky bit)

    当设置粘着位时只有root或者owner才能删除.重命名文件. 示例: 用户apple默认组为fruit. [root@titan ~]# id apple uid=1001(apple) gid=1 ...

  4. Hadoop 之 NameNode 元数据原理

    在对NameNode节点进行格式化时,调用了FSImage的saveFSImage()方法和FSEditLog.createEditLogFile()存储当前的元数据.Namenode主要维护两个文件 ...

  5. 一次关于mongodb性能踩坑的总结

    发现性能问题 上一次导入数据后,发现系统十分的卡顿,但是才仅仅1000多条数据而已,怎么会让系统变得如何的卡顿呢?于是我开始走在排查系统卡顿的原因的道路上. 首先,先定位问题是出现在前端上还是后端上. ...

  6. XML语法小结

    语法结构主要要求: (1)有且仅有一个根元素. 根元素也称文档元素,整个 XML 文档的其他元素都包含在根元素中,并通过嵌套形成树 型结构.除了根元素外,其他元素都是子元素. (2)每个元素必须有开始 ...

  7. HDU 4662 MU Puzzle:找规律

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4662 题意: 初始字符串为"MI". 有三个操作: (1)将'M'之后的所有字符翻 ...

  8. Markdown的简单用法

    Markdown 是一种用来写作的轻量级标记语言,它用简洁的语法代替排版,而不像一般我们用的字处理软件 Word 或 Pages 有大量的排版.字体设置.它使我们专心于码字,用「标记」语法,来代替常见 ...

  9. .NET Core 2.0 是您的最好选择吗?

    本月14日,微软发布.NET Core 2.0 正式版,它的发布意味着.NET Core平台更加成熟,也预示其更美好的未来.本文将分析.NET Core 的特性以及未来发展方向,为开发人员选择在何种平 ...

  10. C语言极易出错的地方(更新中)

    1 时刻记住C语言风格的字符串是以'\0'结尾,无论是在内存的分配还是字符串的赋值上都需要注意