目录

写在前面

文档与系列文章

一级缓存

一个例子

一级缓存管理

总结

写在前面

上篇文章介绍了nhibernate中对象的三种状态,通过对象的三种状态,很容易想到缓存。

什麽是缓存?

有时候,某些数据是会经常需要访问的,像硬盘内部的缓存(暂存器的一种)会将读取比较频繁的一些数据存储在缓存中,再次读取时就可以直接从缓存中直接传输。说白了,缓存是用空间换取时间的一种技术。

文档与系列文章

[Nhibernate]体系结构

[NHibernate]ISessionFactory配置

[NHibernate]持久化类(Persistent Classes)

[NHibernate]O/R Mapping基础

[NHibernate]集合类(Collections)映射 

[NHibernate]关联映射

[NHibernate]Parent/Child

[NHibernate]缓存(NHibernate.Caches)

[NHibernate]NHibernate.Tool.hbm2net

[NHibernate]Nullables

[NHibernate]Nhibernate如何映射sqlserver中image字段

[NHibernate]基本配置与测试 

[NHibernate]HQL查询 

[NHibernate]条件查询Criteria Query

[NHibernate]增删改操作

[NHibernate]事务

[NHibernate]并发控制

[NHibernate]组件之依赖对象

[NHibernate]一对多关系(级联删除,级联添加)

[NHibernate]一对多关系(关联查询)

[NHibernate]多对多关系(关联查询)

[NHibernate]延迟加载

[NHibernate]立即加载

[NHibernate]视图处理

[NHibernate]N+1 Select查询问题分析

[NHibernate]存储过程的使用(一)

[NHibernate]存储过程的使用(二)

[NHibernate]存储过程的使用(三)

[Nhibernate]SchemaExport工具的使用(一)——通过映射文件修改数据表

[Nhibernate]SchemaExport工具的使用(二)——创建表及其约束、存储过程、视图

[Nhibernate]对象状态

一级缓存

关于缓存的详细内容可以查看nhibernate文档[NHibernate]缓存(NHibernate.Caches)

NHibernate session有一个内部的(一级)缓存,存放着它的实体。这些缓存没有共享,因此session被销毁时它的缓存也被销毁了。

NHibernate提供了二级缓存系统;它在SessionFactory级别工作。因此它被同一个SessionFactory产生的session共享。

使用每个请求(request)一个session模式,很多Session可以并发的访问同一个实体,而不用每次都访问数据库,因此性能获得了提升。

可见一级缓存的过期时间是和session的生命周期相同的。

ISession实例创建后即可使用ISession缓存。此后,ISession实例操作数据时,首先查询内置缓存,如果ISession缓存中存在相应数据,则直接使用缓存数据。如果不存在,则查询数据库并把其结果存在缓存中。

为了方便测试,这里改用单元测试的方法进行(也顺便学习一下单元测试,说实话之前很少用这东西,自从使用之后,发现真是太方便了)。

一个例子

1、根据客户id查询符合条件的客户对象。

         /// <summary>
/// 根据客户id查询
/// </summary>
/// <param name="customerID"></param>
/// <returns></returns>
public Customer GetCustomerById(Guid customerID)
{
ISession session = NHibernateHelper.GetSession();
return session.Get<Customer>(customerID);
}

单元测试该方法

 namespace Wolfy.DataUnitTest
{
[TestClass]
public class CustomerDataTest
{
CustomerData _customerData = null;
public CustomerDataTest()
{
_customerData = new CustomerData();
}
[TestMethod]
public void GetCustomerByIdTest()
{
Console.WriteLine("第一次加载");
Customer c1 = _customerData.GetCustomerById(new Guid("DDF63750-3307-461B-B96A-7FF356540CB8"));
Console.WriteLine("第二次加载");
Customer c2 = _customerData.GetCustomerById(new Guid("DDF63750-3307-461B-B96A-7FF356540CB8"));
Assert.AreEqual(c1, c2);
}
}
}

测试结果

当第一次加载数据时,缓存中还没有该数据,则从数据库中查询并将查询的结果放入缓存。第二次查询同一个持久化实例时,缓存中已经存在该持久化实例,应用程序将直接从缓存中获取数据,而不必再次从数据库中读取数据,提高了查询效率。

2、分别从两个会话中查询Customer

构建测试用例,因为获得ISession实例采用的单例模式,如果不进行重置那么Session是同一个对象,所以这里需要在第一次查询后重置ISession,NhibernateHelper代码如下:

 namespace Wolfy.Shop.Data
{
/// <summary>
/// 描述:nhibernate辅助类
/// 创建人:wolfy
/// 创建时间:2014-10-16
/// </summary>
public class NHibernateHelper
{
private static ISessionFactory _sessionFactory;
private static ISession _session;
private static object _objLock = new object();
private NHibernateHelper()
{ }
/// <summary>
/// 创建ISessionFactory
/// </summary>
/// <returns></returns>
public static ISessionFactory GetSessionFactory()
{
if (_sessionFactory == null)
{
lock (_objLock)
{
if (_sessionFactory == null)
{
//配置ISessionFactory
_sessionFactory = (new Configuration()).Configure().BuildSessionFactory();
}
}
}
return _sessionFactory; }
/// <summary>
/// 重置Session
/// </summary>
/// <returns></returns>
public static ISession ResetSession()
{
if (_session.IsOpen)
_session.Close();
_session = _sessionFactory.OpenSession(); ;
return _session;
}
/// <summary>
/// 打开ISession
/// </summary>
/// <returns></returns>
public static ISession GetSession()
{
_sessionFactory = GetSessionFactory();
if (_session == null)
{
lock (_objLock)
{
if (_session == null)
{
_session = _sessionFactory.OpenSession();
}
}
}
return _session;
}
} }

修改GetCustomerById方法

         /// <summary>
/// 根据客户id查询
/// </summary>
/// <param name="customerID"></param>
/// <returns></returns>
public Customer GetCustomerById(Guid customerID)
{
ISession session = NHibernateHelper.GetSession();
return session.Get<Customer>(customerID);
}
/// <summary>
/// 根据客户id查询
/// </summary>
/// <param name="customerID"></param>
/// <returns></returns>
public Customer GetCustomerById2(Guid customerID)
{
ISession session = NHibernateHelper.ResetSession();
return session.Get<Customer>(customerID);
}

单元测试

         [TestMethod]
public void GetCustomerById2Test()
{
Console.WriteLine("Session1 第一次加载");
Customer c1 = _customerData.GetCustomerById(new Guid("DDF63750-3307-461B-B96A-7FF356540CB8"));
Assert.IsNotNull(c1);
Console.WriteLine("Session2 第二次加载");
Customer c2 = _customerData.GetCustomerById2(new Guid("DDF63750-3307-461B-B96A-7FF356540CB8"));
Assert.IsNotNull(c2);
}

运行测试,结果

由上测试可以看出,在两个会话中获取同一持久化实例时,两个会话的缓存是独立的,一个会话的数据操作不会影响到另外一个会话。

从结果我们可以说明虽然这两个会话读取的是同一个实例,但需要至少两次数据库操作(关联的数据表除外),从而说明了Session缓存不是共享的,一个Session的缓存内容只有在本Session实例范围内可用。

3、ISession.Get()和ISession.Load()比较

分别使用Get和Load方法查询某个客户信息。

         /// <summary>
/// 根据客户id查询
/// </summary>
/// <param name="customerID"></param>
/// <returns></returns>
public Customer GetCustomerById(Guid customerID)
{
ISession session = NHibernateHelper.GetSession();
return session.Get<Customer>(customerID);
}
public Customer LoadCustomerById(Guid customerID)
{
ISession session = NHibernateHelper.GetSession();
return session.Load<Customer>(customerID);
}

单元测试

         [TestMethod]
public void GetCustomerByIdTest()
{
Console.WriteLine("----使用Get方式获取Customer实例----");
Customer c1 = _customerData.GetCustomerById(new Guid("DDF63750-3307-461B-B96A-7FF356540CB8"));
Assert.IsNotNull(c1);
Console.WriteLine("输出该客户的id信息:");
Console.WriteLine(c1.CustomerID);
Assert.AreEqual(c1.CustomerID.ToString().ToUpper(), "DDF63750-3307-461B-B96A-7FF356540CB8");
Console.WriteLine("输出该客户的名字:");
Console.WriteLine(c1.NameAddress.CustomerName);
Assert.AreEqual(c1.NameAddress.CustomerName,"wolfy");
}
[TestMethod]
public void LoadCustomerByIdTest()
{
Console.WriteLine("----使用Load方式获取Customer实例----");
Customer c1 = _customerData.LoadCustomerById(new Guid("DDF63750-3307-461B-B96A-7FF356540CB8"));
Assert.IsNotNull(c1);
Console.WriteLine("输出该客户的id信息:");
Console.WriteLine(c1.CustomerID);
Assert.AreEqual(c1.CustomerID.ToString().ToUpper(), "DDF63750-3307-461B-B96A-7FF356540CB8");
Console.WriteLine("输出该客户的名字:");
Console.WriteLine(c1.NameAddress.CustomerName);
Assert.AreEqual(c1.NameAddress.CustomerName, "wolfy");
}

运行单元测试,查看结果

使用ISession.Get()方法立即把对象实例保存到缓存中,使用ISession.Load()方法当你需要使用的时候再访问数据库把这个实例保存在缓存中(有点懒加载的意思,关于Lazy加载可参考前面的文章,Load方法默认是使用Lazy方式加载的)。

一级缓存管理

ISession接口为我们提供了一些常用方法来显式管理一级缓存:

ISession.Evict(object):从缓存中删除指定实例。

ISession.Clear():清空缓存。

ISession.Contains(object):检查缓存中是否包含指定实例。

在CustomerData中添加方法

       /// <summary>
/// 清除session中的缓存
/// </summary>
public void ClearCache()
{
ISession session = NHibernateHelper.GetSession();
session.Clear();
}
/// <summary>
/// 从缓存中移除某个对象
/// </summary>
/// <param name="customer"></param>
/// <returns></returns>
public void RemoveCustomerFromCache(Customer customer)
{
ISession session = NHibernateHelper.GetSession();
session.Evict(customer);
}
    /// <summary>
/// session是否包含customer对象
/// </summary>
/// <param name="customer"></param>
/// <returns></returns>
public bool IsContains(Customer customer)
{
ISession session = NHibernateHelper.GetSession();
return session.Contains(customer);
}

单元测试方法

         [TestMethod]
public void ManagerCacheTest()
{
//1.向ISession中添加两个Customer对象并缓存
Customer customer1 = _customerData.GetCustomerById(new Guid("DDF63750-3307-461B-B96A-7FF356540CB8"));
Customer customer2 = _customerData.GetCustomerById(new Guid("095659B0-8D3F-4DC3-8861-9D7D8A9BA570"));
//2.加载实例后,缓存包含两个实例
Assert.IsTrue(_customerData.IsContains(customer1));
Assert.IsTrue(_customerData.IsContains(customer2));
//3.从缓存中删除Customer1实例
_customerData.RemoveCustomerFromCache(customer1);
Assert.IsFalse(_customerData.IsContains(customer1));
Assert.IsTrue(_customerData.IsContains(customer2));
//4.清空ISession缓存,实例不和缓存关联
_customerData.ClearCache();
Assert.IsFalse(_customerData.IsContains(customer1));
Assert.IsFalse(_customerData.IsContains(customer2));
}

测试结果

该测试,首先加载两个customer实例,此时已将它们都存入一级缓存,首先使用RemoveCustomerFromCache方法,从缓存中将customer1对象移除,然后使用ClearCache方法清空缓存。

总结

本篇文章就到这里,一级缓存是和ISession关联的,多个Session的缓存是不能共享的。本篇文章使用了单元测试的方式进行测试,也是首次使用单元测试,也稍微研究了一下,关于单元测试的东西,算是附加学习的吧。

参考文章

http://www.cnblogs.com/lyj/archive/2008/11/24/1340253.html

[Nhibernate]一级缓存的更多相关文章

  1. NHibernate系列文章八:NHibernate对象一级缓存

    摘要 Nhibernatea缓存非常强大,按照缓存存储在Session对象还是SessionFactory对象分为一级缓存和二级缓存. 一级缓存存在于Session对象里,也叫Session缓存,由S ...

  2. 01-08-01【Nhibernate (版本3.3.1.4000) 出入江湖】NHibernate中的一级缓存

    缓存的范围? 1.事务范围 事务范围的缓存只能被当前事务访问,每个事务都有各自的缓存,缓存内的数据通常采用相互关联的对象形式.缓存的生命周期依赖于事务的生命周期,只有当事务结束时,缓存的生命周期才会结 ...

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

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

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

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

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

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

  6. [Nhibernate]二级缓存

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

  7. NHibernate之一级缓存(第十篇)

    NHibernate的一级缓存,名词好像很牛B,很难.实际上就是ISession缓存.存储在ISession的运行周期内.而二级缓存则存储在ISessionFactory内. 一.ISession一级 ...

  8. NHibernate二级缓存(第十一篇)

    NHibernate二级缓存(第十一篇) 一.NHibernate二级缓存简介 NHibernate由ISessionFactory创建,可以被所有的ISession共享. 注意NHibernate查 ...

  9. [原创]关于mybatis中一级缓存和二级缓存的简单介绍

    关于mybatis中一级缓存和二级缓存的简单介绍 mybatis的一级缓存: MyBatis会在表示会话的SqlSession对象中建立一个简单的缓存,将每次查询到的结果结果缓存起来,当下次查询的时候 ...

随机推荐

  1. logback配置详解2<appender>

    logback 常用配置详解(二) <appender> <appender>: <appender>是<configuration>的子节点,是负责写 ...

  2. 开源一个windows下的定时任务框架,简单粗暴好用。

    这里是你想要的功能: 支持插件,将你要执行的任务编译成程序集放到框架的根目录下,再进行简单的配置就行了. 支持Corn表达式.想让任务在什么时候执行就在什么时候执行. 支持安装成windows ser ...

  3. Linux Core Dump

    当程序运行的过程中异常终止或崩溃,操作系统会将程序当时的内存状态记录下来,保存在一个文件中,这种行为就叫做Core Dump(中文有的翻译成“核心转储”).我们可以认为 core dump 是“内存快 ...

  4. C++系统预定义4个用于标准数据流对象

    C++系统预定义4个用于标准数据流对象 cin   cout   cerr   clog C++里关于cerr,clog,cout三者的区别: cerr(无缓冲标准错误)-----没有缓冲,发送给它的 ...

  5. 关于调整input里面的输入光标大小

    input输入框用一个背景图模拟,设置height和line-height一样的高度,使里面的输入文字能够居中, 在FF下出现的情况是:点击input时,输入光标其实上跟input的height一样高 ...

  6. [No000077]打造自己的Eclipse

    下载官网的Eclipse IDE for Java EE Developers 在根目录下的eclipse.ini文件中添加"-Dfile.encoding=UTF-8", 作用: ...

  7. 转: 深入理解Linux修改hostname

    from: http://www.cnblogs.com/kerrycode/p/3595724.html 写的相当详细!!! 深入理解Linux修改hostname 2014-03-12 10:17 ...

  8. android第一行代码-6.自定义控件的实现

    0.假设一个应用中标题栏控件都是共用的,如果每个activity都需要设置button,绑定方法,那代码就会很臃肿.那我们可以自定义控件,然后继承这个控件就行了. 自定义控件为TitleLayout, ...

  9. Git的Patch功能

    转自:http://www.cnblogs.com/y041039/articles/2411600.html UNIX世界的软件开发大多都是协作式的,因此,Patch(补丁)是一个相当重要的东西,因 ...

  10. 由12306动态验证码想到的ASP.NET实现动态GIF验证码(附源码)

    背景: 12306网站推出“彩色动态验证码机制”,新版验证码不但经常出现字符叠压,还不停抖动,不少人大呼“看不清”,称“那个验证码,是毕加索的抽象画么!”铁总客服则表示:为了能正常购票只能这样.而多家 ...