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语句生成。这说明二级缓存起作用了。
12. 现在改变cache.use_second_level_cache设置为false,再次运行程序。这次,有两个select语句发送到数据库,如下图所示:
很明显,除了insert语句外,还有两个select语句:每个session对象一个,用来加载product实体。
在这个例子中,我们学会了如何配置程序以便NHibernate使用二级缓存,也学会了如何配置实体映射以便它们可以被缓存到二级缓存中。
转载于:https://www.cnblogs.com/nianming/archive/2011/11/17/2253201.html
NHibernate初学者指南(10):一级和二级缓存相关推荐
- NHibernate初学者指南(15):使用LINQ to NHibernate提供程序查询数据
在前面的<NHibernate初学者指南(8):增删查改>一文中简单的提到了查询一个实体的Get<T>和Load<T>方法以及查询实体列表的Query<T&g ...
- 深入浅出 MyBatis 的一级、二级缓存机制
一.MyBatis 缓存 缓存就是内存中的数据,常常来自对数据库查询结果的保存.使用缓存,我们可以避免频繁与数据库进行交互,从而提高响应速度. MyBatis 也提供了对缓存的支持,分为一级缓存和二级 ...
- Mybatis3.4.x技术内幕(二十二):Mybatis一级、二级缓存原理分析
2019独角兽企业重金招聘Python工程师标准>>> Mybatis的一级缓存,指的是SqlSession级别的缓存,默认开启:Mybatis的二级缓存,指的是SqlSession ...
- 【mybatis】Mybatis中的一级、二级缓存
[mybatis]简介 [mybatis]mybatis & mybatis-plus & hibernate的区别 [mybatis]核心成员分析 [mybatis]Mybatis的 ...
- mybatis和hibernate的一级、二级缓存
MyBatis一级缓存: hibernate一级缓存: 基本差不多 HashMap本地缓存,作用域为session,session级别的缓存,通过get,update可以将对象放到一级缓存中,当 Se ...
- mybatis一级,二级缓存。缓存带来的脏读问题
title 1. 关于缓存的介绍 2. 一级缓存,默认开启,session级别 3. 二级缓存,mapper 的namespace级别 1. 关于缓存的介绍 Mybatis一级缓存的作用域是同一个Sq ...
- Mybatis开启一级、二级缓存
1.缓存 (1)概念:在内存中开辟的一个区域,用于存放数据,在内存中存放的数据叫做缓存. (2)好处:内存读取速度远快于硬盘,合理利用缓存,可以极大的提高查询的效率. 1.1 一级缓存 一级缓存的作用 ...
- NHibernate初学者指南(6):映射模型到数据库之方式二
使用Fluent NHibernate自动映射 使用Fluent NHibernate自动映射,首先要将映射的实体放到一个命名空间中,这使得通知AutoMapper哪些实体和值对象包含在映射中更容易. ...
- NHibernate初学者指南(1):开篇
这个系列所有的文章都是根据NHibernate 3 Beginner's Guide一书完成的,主要记录自己的学习经历,方便以后的查阅.鉴于<Entity Framework 4 in Acti ...
最新文章
- P1132 数字生成游戏
- C++11中rvalue references的使用
- bzoj3545 Peaks
- 洛谷 P2359 三素数数
- Dubbo 序列化协议 5 连问,这谁接得住啊?
- ps软件怎么测试性能,怎么样提高Photoshop性能,让PS软件快速启动
- Android跑马灯
- python 测试用例怎么输入两个_python selenium多个测试用例
- 基于kb的问答系统_1KB以下基于表的Q学习
- 赞扬精心设计:基于属性的测试如何帮助我成为更好的开发人员
- 解决:which: no java in (/root/chengxu/maven/apache-maven-3.5.2/bin:/usr/local/sbin:/usr/local/bin:/usr
- php 判断同时存在英文跟数字,php判断输入是否是纯数字,英文,汉字的方法
- linux 的sed命令解释 sed ':t;N;s/\n/,/;b t' 将换行符换成逗号
- Chelly的串串专题
- FusionGAN图像融合代码学习
- 通过 purge_relay_logs 自动清理relaylog
- 2021最新申请苹果的公司开发者账号
- iOS音视频播放-AVPlayer简单使用
- Win10下媲美apt的包管理工具 Scoop 的安装以及常用软件清单
- 建模助手 | 关于REVIT的小技巧,你知道多少?