博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
NHibernate教程(21)——二级缓存(下)
阅读量:5024 次
发布时间:2019-06-12

本文共 6600 字,大约阅读时间需要 22 分钟。

本节内容

  • 引入
  • 使用NHibernate二级缓存
  • 启用缓存查询
  • 管理NHibernate二级缓存
  • 结语

引入

这篇我还继续上一篇的话题聊聊NHibernate二级缓存剩下的内容,比如你修改、删除数据时,二级缓存是什么策略呢?我们如果使用缓存查询呢?如何管理NHibernate二级缓存呢?

使用NHibernate二级缓存

不知道具体配置的请转到观看上一篇的内容,这篇我们再写几个测试,来看看NHibernate二级缓存一些细节:

测试1:更新数据

当我们启用二级缓存时,如果第一次把数据查询出来,然后修改了这个数据,这时二级缓存中的数据是什么呢?我们写一个测试看看究竟吧:

[Test]public void SessionFactoryCacheUpdateTest(){    string firstname="YJingLee";    using (_session)    {        using (var tx = _session.BeginTransaction()) { Console.WriteLine("第一次读取持久化实例"); Customer customer1 = _session.Get
(1); Console.WriteLine("更新持久化实例"); customer1.Name.Firstname =firstname; tx.Commit(); } } ResetSession(); Console.WriteLine("第二次读取持久化实例"); using (_session) { Customer customer2 = _session.Get
(1); Console.WriteLine("新FirstName为:{0}",customer2.Name.Firstname); Assert.AreEqual(customer2.Name.Firstname, firstname); } }

输出结果:

分析一下:在第一次查询数据时,由于一级、二级缓存中都不存在需要的数据,这时NHibernate从数据库中查询数据。我们修改这条数据并提交到数据库中,NHibernate执行一条更新语句,由于我们设置了读写缓存策略,NHibernate更新了二级缓存中的数据内容,第二次读取这条数据,NHibernate首先从内置缓存(一级缓存)中查找是否存在所需要数据,由于不是在同一个ISession中,所以内置ISession缓存中不存在所需数据,NHibernate则查询二级缓存,这时由于第一次查询了这条数据,所以在二级缓存中存在所需数据,则直接使用缓存中数据。这时缓存中的数据也是更新的。

至于删除、插入数据我想也是类似的。这里我就不写测试了。

启用缓存查询

在NHibernate中,除了缓存持久化类和集合外,查询结果集也可以缓存。如果程序中经常使用同样的条件查询数据,则可以使用查询缓存。在配置文件中可以指定启动查询缓存

true

查询缓存后,NHibernate将创建两个缓存区域。一个用于保存查询结果集,由NHibernate.Cache.StandardQueryCache实现。一个用来保存最近更新的查询表的时间截,由NHibernate.Cache.UpdateTimestampsCache实现。

查询缓存中的结果集并不是永久有效的。当缓存的查询语句对应的数据库发生改变时,该缓存结果随之失效。因而对大多数查询而言,查询缓存的益处不是很大,所以NHibernate在默认情况下不对查询进行缓存。

如果需要对查询缓存,还需要显式的使用IQuery.SetCacheable(true)方法。IQuery调用这个方法后,NHibernate将根据查询语句、查询参数、结果集起始范围等信息组成一个IQueryKey。接着根据这个IQueryKey到查询缓存中查找相应数据,查询成功则直接返回查找结果。否则,查询数据库,获取结果集,并把结果集根据IQueryKey放入查询缓存。如果IQueryKey数据发生改变(增加、删除、修改等),这些IQueryKey及其对象的结果集将从缓存中删除。

测试2:显式启用缓存查询

这个例子显式使用IQuery.SetCacheable(true)方法缓存查询结果,第二次查询相同条件时,直接从缓存查询中读取。

[Test]public void QueryCacheTest(){    using (_session)    {        Console.WriteLine("第一次查询某数据,显式缓存查询结果");        IList
customers = _session.CreateQuery("from Customer c where c.CustomerId > 2") .SetCacheable(true) .List
(); Assert.AreEqual(11, customers.Count); } ResetSession(); using (_session) { Console.WriteLine("第二次查询某数据,显式缓存查询结果"); IList
customers = _session.CreateQuery("from Customer c where c.CustomerId > 2") .SetCacheable(true) .List
(); Assert.AreEqual(11, customers.Count); } }

看看结果

由于我们显式缓存查询结果,在第二次查询时,直接使用二级缓存中的结果集。

测试3:指定命名缓存区域

我们还可以使用.SetCacheRegion("cacheRegion")给查询缓存指定了特定的命名缓存区域,该查询缓存的缓存策略将由二级缓存的命名区域负责:

[Test]public void QueryCacheTest(){    using (_session)    {        Console.WriteLine("第一次查询某数据,显式缓存查询结果");        IList
customers = _session.CreateQuery("from Customer c where c.CustomerId > 2") .SetCacheable(true) .SetCacheRegion("queryCache") .List
(); Assert.AreEqual(11, customers.Count); } ResetSession(); using (_session) { Console.WriteLine("第二次查询某数据,显式缓存查询结果"); IList
customers = _session.CreateQuery("from Customer c where c.CustomerId > 2") .SetCacheable(true) .SetCacheRegion("queryCache") .List
(); Assert.AreEqual(11, customers.Count); } }

测试结果说明:第一次查询出来的结果集被存储在名为queryCache的缓存区域,第二次同样在这个缓存区域里寻找需要数据,如果第二次没有指定或者指定别的缓存区域则没有需要的数据,就要到数据库中查询了。

测试4:命名查询

可以在映射文件中定义命名查询,<query>元素提供了很多属性,可以用于缓存结果,这里,我举一个例子吧,在Customer.hbm.xml映射文件中定义名为selectCustomer的查询由于查询所有Customer并启用缓存查询,缓存模式为默认方式(下面有说明)

from Customer

编写一个方法:

[Test]public void NamedQueryCacheTest(){    using (_session)    {        Console.WriteLine("--->第一次使用命名查询");        IList
customers = _session.GetNamedQuery("selectCustomer") .List
(); } ResetSession(); using (_session) { Console.WriteLine("--->第二次使用命名查询"); IList
customers = _session.GetNamedQuery("selectCustomer") .List
(); } }

测试结果:第二次直接使用二级缓存中的结果集。

NHibernate提供的查询(HQL、条件查询、原生SQL查询)都类似,我在这里就不重复举例了,大家可以测试下。

管理NHibernate二级缓存

NHibernate二级缓存由ISessionFactory创建并由ISessionFactory自行维护。我们使用NHibernate操作数据时,ISessionFactory能够自动同步缓存,保证缓存的有效性。但是当我们批量操作数据时,往往NHibernate不能维护缓存持久有效。ISessionFactory提供了可编程方式的缓存管理方法。

ISessionFactory提供了一系列的EvictXXX()方法可以方便的从二级缓存中删除一个实例、删除一个集合、一个命名缓存等操作

  • Evict(persistentClass):从二级缓存中删除persistentClass类所有实例
  • Evict(persistentClass, id):从二级缓存中删除指定的持久化实例
  • EvictEntity(entityName):从二级缓存中删除命名实例
  • EvictCollection(roleName):从二级缓存中删除集合
  • EvictCollection(roleName, id):从二级缓存中删除指定的集合
  • EvictQueries():从二级缓存中刷新全部查询结果集
  • EvictQueries(cacheRegion):从二级缓存中刷新指定查询结果集

ISession内置缓存可以共享ISessionFactory缓存,通过指定ISession的CacheMode可以控制ISession和ISessionFactory的交互方式。ISession可以通过以下五种方式和ISessionFactory交互:

  • Ignore:更新数据时将二级缓存失效,其它时间不和二级缓存交互
  • Put:向二级缓存写数据,但不从二级缓存读数据
  • Get:从二级缓存读数据,仅在数据更新时向二级缓存写数据
  • Normal:默认方式。从二级缓存读/写数据
  • Refresh:向二级缓存写数据,想不从二级缓存读数据,通过在配置文件设置cache.use_minimal_puts从数据库中读取数据时,强制二级缓存刷新

测试5:管理NHibernate二级缓存

我们可以使用ISessionFactory提供了一系列的EvictXXX()方法从二级缓存中删除一个实例,看看这个例子在第一次读取持久化实例时,结果集保存在二级缓存中,使用Evict方法从二级缓存中删除所有持久化实例,第二次查询相同数据,二级缓存中不存在则重新从数据库中查询了~~

[Test]public void SessionFactoryManageTest(){    ISessionFactory _sessionFactory = (new Configuration()).Configure().BuildSessionFactory();    Console.WriteLine("第一次读取持久化实例"); using (ISession _session = _sessionFactory.OpenSession()) { Customer customer1 = _session.Get
(1); Customer customer2 = _session.Get
(2); } Console.WriteLine("从二级缓存中删除Customer类所有实例"); _sessionFactory.Evict(typeof(Customer)); //也可以_sessionFactory.EvictEntity("DomainModel.Entities.Customer"); Console.WriteLine("第二次读取持久化实例"); using (ISession _session = _sessionFactory.OpenSession()) { Customer customer1 = _session.Get
(1); } }

输出结果:

测试6:强制刷新缓存区域

我们使用ISession提供的.SetCacheMode(CacheMode.Refresh) 方法可以强制刷新缓存区域,这样可以避免数据不一致问题~~

[Test]public void QueryCacheTest(){    using (_session)    {        Console.WriteLine("第一次查询某数据,显式缓存查询结果");        IList
customers = _session.CreateQuery("from Customer c where c.CustomerId > 2") .SetCacheable(true) .SetCacheRegion("queryCache") .List
(); Assert.AreEqual(11, customers.Count); } ResetSession(); using (_session) { Console.WriteLine("第二次查询某数据,显式缓存查询结果"); Console.WriteLine("----指定特定的命名缓存区域并强制刷新缓存区域----"); IList
customers = _session.CreateQuery("from Customer c where c.CustomerId > 2") .SetCacheable(true) .SetCacheRegion("queryCache") .SetCacheMode(CacheMode.Refresh) .List
(); Assert.AreEqual(11, customers.Count); } }

输出结果:

这篇没有什么深入,不好意思啦~~

结语

好了,这篇就到这里吧!揭晓了比如你修改、删除数据时,二级缓存是什么策略?我们如果使用查询缓存?如何管理NHibernate二级缓存?我们合理使用缓存,可以大幅度地提高程序的性能。

转载于:https://www.cnblogs.com/zhengwei-cq/p/7388551.html

你可能感兴趣的文章
SELECT INTO 和 INSERT INTO SELECT 两种表复制语句(转载)
查看>>
数据结构上机任务
查看>>
centos7上安装mysql
查看>>
浮动的label
查看>>
Python --文件的读写
查看>>
乱码问题
查看>>
hdu1671Phone List(字典树)
查看>>
访客至上的Web、移动可用性设计--指导原则
查看>>
常用模块一
查看>>
类和对象
查看>>
追剧《大秦帝国》之感
查看>>
[转] Python Traceback详解
查看>>
SpringMVC中接收不同类型的数据
查看>>
Windows 创建 Tomcat 服务
查看>>
ArchLinux安装开源VMware Tools
查看>>
系统用户分析模型
查看>>
DB2 锁升级示例1
查看>>
16.RDD实战
查看>>
MainFrame知识小结(20120210)—dfsort/syncsort中的数据类型
查看>>
jsp题库 (一)小测(25/21)
查看>>