NHibernate初学者指南(10):一级和二级缓存

一级缓存

为了获得更好的性能,NHibernate智能地缓存数据。NHibernate有不同的缓存机制起作用,最重要的就是一级缓存。每个session对象维持一个一级缓存,session对象创建时缓存创建,session对象释放时缓存销毁。

缓存只不过是一个哈希表。哈希表根据唯一键存储值,值可以根据唯一键检索。

一个实体由它的ID唯一标识,如果两个实体类型相同,ID也相等,那么这两个实体是相等的。NHibernate要求两个相同类型的对象不能有相同的ID。原因是,如果允许系统有相同ID的两个实例,那么就会将系统置于不一致的状态中。有了这个条件,NHibernate就可以执行下面的操作了:

NHibernate session对象从数据库中加载指定ID的实体,然后放到一级缓存中,访问该实体的键是它的ID值。当系统再次从数据库中加载同一个实体时,session对象首先检查它的缓存,如果实体已经存在于缓存中,NHibernate就返回缓存的实例。只有实体不在缓存时,NHibernate session对象才从数据库中加载实体。看下面的过程:

  • 程序请求session ID为1的product
  • session问一级缓存:“有ID为1的product吗?”
  • 一级缓存回答说:“没有”
  • session就从数据库中加载ID为1的product
  • session将product放入一级缓存,键为product的ID值
  • session返回给程序product实例
  • 程序执行更多的操作
  • 程序再次请求session ID为1的product
  • session问一级缓存:“有ID为1的product吗”
  • 一级缓存回答说:“有”
  • session就使用ID作为键从缓存中加载ID为1的product,并返回给程序

我们使用下面的代码从数据库中加载实体并隐式的使NHibernate session将它存储到一级缓存:

var product = sesson.Get<Product>(1); 

之后的Get操作不会引起NHibernate查询数据库而是从一级缓存中检索对象。

清除缓存

我们使用下面的语句请求session从一级缓存中移除一个实体:

session.Evict(product); 

如果想完全的清除缓存,可以使用下面的代码:

session.Clear(); 

上述语句应该仅在特殊情况下使用,因为,如果使用不当会导致显著的性能下降。建议只在写测试代码时使用这些操作。

刷新缓存中的实体

如果想刷新一级缓存中的单个实体,那么可以使用下面的语句:

session.Refresh(product);

上面的代码重新从数据库中加载product实体的状态,这在session打开的同时数据库里的实体被其他程序更改的情况下非常有意义。

二级缓存

我们已经看到NHibernate提供了非常有效的方式缓存数据。可惜,一级缓存绑定到session对象,也就是说每次session被释放,所有的缓存数据就会丢失。二级缓存定义在session工厂级别的,只要session工厂没有被释放缓存就一直存在。一旦实体加载,二级缓存就被激活,实体对所有的session(同session工厂的)都可用。这样,只要实体在二级缓存中,NHibernate就不会从数据库加载实体,直到它从缓存中移除。

启动二级缓存,我们就要定义使用哪个缓存提供程序。二级缓存有各种实现。我们的例子中使用基于哈希表的缓存,它包含在核心的NHibernate程序集中。请注意,不应该在生产级的代码中使用这种缓存提供程序,仅仅用在测试中。参看后面的“二级缓存的实现”部分,选择哪个实现最适合你;然而,如果你改变了缓存提供程序,你不用修改你的代码。

使用下面的代码只会引发NHibernate访问一次数据库检索ID为1的product,即使我们使用两个不同的session实例:

using (var session1 = sessionFactory.OpenSession()) 
{ 
var product = session1.Get<Product>(1); 
}
using (var session2 = sessionFactory.OpenSession()) 
{ 
var product = session2.Get<Product>(1); 
} 

第二个Get操作会从二级缓存中获取product实体。然而要注意的是,如果没有启动二级缓存,上面的代码会访问两次数据库。

另外,启动二级缓存,必须相应的配置NHibernate。配置的详细内容会在后面介绍。我们还必须映射实体为可缓存的。如果使用fluent映射映射实体,那么添加到映射的必要语句是:

Cache.ReadWrite(); 

只有显示配置的实体才会缓存在二级缓存中。

缓存区域

如果不使用缓存区域,那么二级缓存只能整体清除。如果需要清除二级缓存的一部分,就得使用缓存区域。缓存区域根据它们的名字区分。我们可以将任何数量的不同查询放在命名的缓存区域中。清除一个缓存区域的命令如下:

sessionFactory.EvictQueries("My Region"); 

当前使用的sessionFactory是session工厂的实例,My Region是缓存区域的名字。

二级缓存的实现

所有的二级缓存提供程序都是NHibernate contributions项目的一部分。下面列表给出了一些支持的提供程序的简短描述。

  • SysCache:使用System.Web.Caching.Cache作为缓存提供程序。也就是说可以依靠ASP.NET的缓存功能来理解它如何工作。
  • SysCache2:和NHibernate.Caches.SysCache一样,使用ASP.NET缓存。这个提供程序也支持SQL基于依赖过期,意思是当数据库里的相关数据发生改变不可能自动地配置某些缓存区域。
  • Velocity:它是Microsoft Windows Server App Fabric的一部分,是一组构建、扩展和管理基于IIS的web应用程序的综合服务。
  • Prevalence:使用Bamboo.Prevalence作为缓存提供程序。Bamboo.Prevalence是由Klaus Wuestefeld在Prevayler中提出的对象流行概念的.NET实现。Bamboo.Prevalence提供针对CLR的确定性系统的透明对象持久化。它为智能客户端应用程序提供持久化的缓存。
  • MemCache:Memcached.Memcahed是一个高性能,分布式内存对象缓存系统,但是旨在通过减轻数据库负载加速动态web应用程序。根本上说,就是一个分布式的哈希表。

实例—使用二级缓存

在这个例子中,我们使用NHibernate的二级缓存实现一个非常简单的例子。我们在例子中使用哈希表缓存提供程序,但是在生产级代码中不要使用这个提供程序!

1. 在SSMS中创建一个数据库:SecondLevelCacheSample。

2. 打开Visual Studio,创建一个Console Application:SecondLevelCacheSample。

3. 添加对NHibernate.dll,FluentNHibernate.dll和NHibernate.ByteCode.Castle.dll程序集的引用。

4. 在项目中创建Domain文件夹。

5. 在Domain文件夹中创建一个类文件Product.cs,添加如下代码:

public class Product
{public virtual int Id { get; set; }public virtual string Name { get; set; }public virtual decimal UnitPrice { get; set; }public virtual int ReorderLevel { get; set; }public virtual bool Discontinued { get; set; }
}

6. 在Domain文件夹中添加一个ProductMap.cs类文件用来映射Product实体,代码如下:

public class ProductMap : ClassMap<Product>
{public ProductMap(){Cache.ReadWrite();Id(x => x.Id).GeneratedBy.HiLo("1000");Map(x => x.Name);Map(x => x.UnitPrice);Map(x => x.ReorderLevel);Map(x => x.Discontinued);}
}

注意在映射中添加了Cache.ReadWrite()语句用来告诉NHibernate为Product实体使用二级缓存。

7. 在Program类中添加一个ISessionFactory类型的静态字段,如下:

private static ISessionFactory sessionFactory;

8. 在Program类中添加一个静态方法:ConfigureSystem。这个方法包含配置NHibernate的一般代码和二级缓存的代码。如下面的代码所示:

private static void ConfigureSystem()
{const string connString ="server=.;database=SecondLevelCacheSample;" +"user id=sa;password=sasa;";var configuration = Fluently.Configure().Database(MsSqlConfiguration.MsSql2008.ConnectionString(connString).ShowSql).Mappings(m => m.FluentMappings.AddFromAssemblyOf<Product>()).BuildConfiguration();configuration.Properties["cache.provider_class"] = "NHibernate.Cache.HashtableCacheProvider";configuration.Properties["cache.use_second_level_cache"] = "true";var exporter = new SchemaExport(configuration);exporter.Execute(true, true, false);sessionFactory = configuration.BuildSessionFactory();
}

配置二级缓存的代码中,第一个是告诉NHibernate使用哪个二级缓存提供程序。它是一个键值对。值是实现二级缓存提供程序类的全路径。在我们的例子中不需要定义程序集,因为该提供程序在NHibernate程序集内。第二个是启用或禁止二级缓存的使用。注意,从技术上来说,第二个配置不需要,因为它的默认值是true。

9. 在Program类中,创建一个TestLoadEntity的静态方法,代码如下:

private static void TestLoadEntity()
{int productId;var product = new Product{Name = "Apple",UnitPrice = 1.55m,ReorderLevel = 100,Discontinued = false};using (var session = sessionFactory.OpenSession()){using (var tx = session.BeginTransaction()){productId = (int)session.Save(product);tx.Commit();}}using (var session1 = sessionFactory.OpenSession()){var product1 = session1.Get<Product>(productId);}using (var session2 = sessionFactory.OpenSession()){var product2 = session2.Get<Product>(productId);}
}

10. 在Main方法中调用ConfigureSystem和TestLoadEntity方法:

static void Main(string[] args)
{ConfigureSystem();TestLoadEntity();Console.Write("\r\nHit enter to exit:");Console.ReadLine();
}

11. 运行程序,验证没有select语句生成。这说明二级缓存起作用了。

QQ截图20111117205732

12. 现在改变cache.use_second_level_cache设置为false,再次运行程序。这次,有两个select语句发送到数据库,如下图所示:

QQ截图20111117210126

很明显,除了insert语句外,还有两个select语句:每个session对象一个,用来加载product实体。

在这个例子中,我们学会了如何配置程序以便NHibernate使用二级缓存,也学会了如何配置实体映射以便它们可以被缓存到二级缓存中。

转载于:https://www.cnblogs.com/nianming/archive/2011/11/17/2253201.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/267473.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Freemarker模板引擎

模板引擎的实质就是将页面结构提前写好&#xff0c;然后将数据渲染到模板上生成一个静态页面&#xff0c;这样一来&#xff0c;下次就可以 直接访问静态文件&#xff0c;不用进行额外的获取数据的操作&#xff08;例如&#xff1a;访问数据库&#xff09;&#xff0c;这样大大提…

postgresql主从备份_基于windows平台的postgresql主从数据库流备份配置

基于windows平台的postgresql主从数据库流备份配置因工作需要&#xff0c;需要搞pg数据库的主从备份&#xff0c;领导给了个方向使用流备份&#xff0c;于是开始朝着这个方向进发。鸣谢大佬A_ccelerator的博客一、配置主从库1.环境准备对于 pg 的主从库配置&#xff0c;建议是使…

msvcrt.lib和LIBCD.lib链接冲突

今天在移植一个开源代码到windows的VC6工程&#xff0c;编译时出现了这些奇怪的LINK错误。 msvcrt.lib(MSVCRT.dll) : error LNK2005: _toupper already defined in LIBCD.lib(toupper.obj)msvcrt.lib(MSVCRT.dll) : error LNK2005: _tolower already defined in LIBCD.lib(to…

jq获取最后一个子节点_如何选择jQuery中的最后一个子元素?

牧羊人nacy如果要选择最后一个子元素&#xff0c;并且需要具体说明元素类型&#xff0c;则可以使用选择器last-of-type这是一个例子&#xff1a;$("div p:last-of-type").css("border", "3px solid red");$("div span:last-of-type").…

面向对象 - 继承/组合 - 总结

面向对象 - 继承:1.继承: 类与类之间的关系 什么是什么的关系 eg:人是动物 狗是动物 功能: 解决代码重用问题, 创建新类的方式, 类: 可继承一个或多个父类: 父类 基类/超类 类 派生类/子类 类: 对象之间相似的特征 父类:…

巧妙的有css合并图片解决tab切换的背景图片

巧妙的有css合并图片解决tab切换的背景图片 有时候做tab切换的时候 会碰到下面的这种情况 我截个图过来看看 tab切换 打开页面时候 茶庄介绍 及鼠标移上去时候 是上面这样的效果 当鼠标移下来的时候 是下面这样的 茶庄介绍 就变成这样的背景 一刚开始做这样的 我就想到用j…

XUPT_STA2018(部分题解)

A - 一方通行和最大公约数I CodeForces - 664A 作为学园都市最强的lv5&#xff0c;一方通行必须解决一道数学题才能接触last order身上植入的病毒&#xff0c;请你帮他解决这个问题。给出两个整数a,b 求出[a,b]区间中所有整数的最大公约数。输入输入包括一行&#xff0c;一…

java mongodb drivers 2升级到3_JAVA从头开始一基础梳理(3-2)

本章为大家介绍类的特性。首先&#xff0c;第一个特性----封装。在这个类别中&#xff0c;属性id 与属性 color 是可以被外部直接访问和修改的&#xff0c;比如可以看到&#xff0c;事实上这样的内容是错误的&#xff0c;我们需要在定义属性值时需要加入验证等等操作&#xff0…

C 语言第6节课

我上课C语言的第6节的笔记 &#xff1a;C语言真的需要多做多练多理解&#xff0c;不然真的学不懂.记不住呀。第一题&#xff1a;睇图片解题。main(){int x,y;scanf("%d",&x);if(x<0)printf("y%d",0);if(x>0&&x<5)printf("y%d&qu…

activiti idea 请假流程_IDEA开发流程Activiti需要注意的一些坑

1、慎用IDEA2020最新版本IDEA2020最新版本迎来了重大升级&#xff0c;对java和spring有了更好更强大的开发支持&#xff0c;但是对于Activiti流程开发却不再支持&#xff0c;可能是因为actiBPM插件太老&#xff0c;或者IDEA2020对插件支持做了规范要求等等&#xff0c;请各位喜…

VIPCA无法运行

本文转自ITPUB上一兄弟总结&#xff0c;以备查询。 今天一早来&#xff0c;同事说他周末在安装 rac 出问题了&#xff0c;始终无法使用vipca 创建 vip资源 &#xff0c; 叫我帮忙看看。 他用的是 vmware server 2.0 搭建 虚拟 rac 。 一. 环境如下  OS: Red Hat Enterprise …

python加权最小二乘_【Python】统计科学之加权最小二乘法

首页专栏python文章详情0统计科学之加权最小二乘法张俊红发布于 今天 10:03今天这篇来讲讲加权最小二乘法(WLS)&#xff0c;加权最小二乘是在普通的最小二乘回归(OLS)的基础上进行改造的&#xff0c;主要是用来解决异方差问题的。OLS的常规形式如下&#xff1a;我们在前面讲过O…

删除电脑中的mysql数据库吗_【数据库】怎么彻底删除mysql服务?

彻底删除mysql服务的步骤&#xff1a;1、关闭mysql服务在cmd命令行输入以下命令net stop mysql或者 我的电脑右键->管理->服务&#xff0c;进入后手动关闭。2、删除MySQL服务在cmd中&#xff0c;输入sc delete mysql&#xff0c;删除服务。但是MYSQL服务只是显示禁用状态…

mysql主从配置 简书_Mysql主从配置,实现读写分离-Go语言中文社区

转载&#xff1a;https://www.cnblogs.com/alvin_xp/p/4162249.html大型网站为了软解大量的并发访问&#xff0c;除了在网站实现分布式负载均衡&#xff0c;远远不够。到了数据业务层、数据访问层&#xff0c;如果还是传统的数据结构&#xff0c;或者只是单单靠一台服务器扛&am…

continue 的用户及实例

continue 跳出本次循环&#xff0c;继续下一次循环 “break”是跳出整个循环 实例1&#xff1a; for i in range(10): if i <5: continue    #这里条件是小于5&#xff0c;满足条件的就跳出了本次循环&#xff0c;不在执行print&#xff0c;所以最终打印的是5…

mysql报错注入实战_MySQL手工注入实战

实战记录&#xff0c;日本某站注入点 and 语句测试and11 返回正常&#xff0c;and2跳回首页&#xff0c;可能过滤了用 ’ 测试返回错误页面判断为注入点order by语句查询字段数测试字段数为9and 12 UNION SELECT 1,2,3,4,5,6,7,8,9报错联合查询语句&#xff0c;查询显示位2、3为…

20个简约风格网站设计作品欣赏

这篇文章收集了20个简洁清爽的网站设计作品案例&#xff0c;设计师们能够通过这些优秀的网页设计作品获得灵感&#xff0c;进而设计出更精美&#xff0c;更具有创意的网站作品&#xff0c;一起欣赏。vnsagaPure – Minimal WordPress themeAssemblydeladeeus design studioHocu…

python 股票自动交易从零开始_Python股票自动交易从零开始

课程目录1.Python股票自动交易从零开始~第一集~简介(Av24528809,P1).mp42.Python股票自动交易从零开始~第二集~安装工具包(Av24528809,P2).mp43.Python股票自动交易从零开始~第二集番外~配置Mac工作环境(Av24528809,P3).mp44.Python股票自动交易从零开始~第三集~获得股票列表-A…

python 银行工作_Python:银行系统实战(一)

最近突然抽筋想做一下大学时候做过的银行系统实战~代码就发在这里啦~学弟学妹们请查收~不过是python版本的&#xff0c;你们也用不上。。。两个py文件&#xff0c;一个是后台系统处理的&#xff0c;一个是总控py文件如下&#xff1a;view.py 内容如下&#xff1a;import timecl…

深入剖析LinkedList:揭秘底层原理

文章目录 一、 概述LinkedList1.1 LinkedList简介1.2 LinkedList的优点和缺点 二、 LinkedList数据结构分析2.1 Node节点结构体解析2.2 LinkedList实现了双向链表的原因2.3 LinkedList如何实现了链表的基本操作&#xff08;增删改查&#xff09;2.4 LinkedList的遍历方式 三、 …