zoukankan      html  css  js  c++  java
  • [Nhibernate]一级缓存

    目录

    写在前面

    文档与系列文章

    一级缓存

    一个例子

    一级缓存管理

    总结

    写在前面

    上篇文章介绍了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查询符合条件的客户对象。

     1         /// <summary>
     2         /// 根据客户id查询
     3         /// </summary>
     4         /// <param name="customerID"></param>
     5         /// <returns></returns>
     6         public Customer GetCustomerById(Guid customerID)
     7         {
     8             ISession session = NHibernateHelper.GetSession();
     9             return session.Get<Customer>(customerID);
    10         }

    单元测试该方法

     1 namespace Wolfy.DataUnitTest
     2 {
     3     [TestClass]
     4     public class CustomerDataTest
     5     {
     6         CustomerData _customerData = null;
     7         public CustomerDataTest()
     8         {
     9             _customerData = new CustomerData();
    10         }
    11         [TestMethod]
    12         public void GetCustomerByIdTest()
    13         {
    14             Console.WriteLine("第一次加载");
    15             Customer c1 = _customerData.GetCustomerById(new Guid("DDF63750-3307-461B-B96A-7FF356540CB8"));
    16             Console.WriteLine("第二次加载");
    17             Customer c2 = _customerData.GetCustomerById(new Guid("DDF63750-3307-461B-B96A-7FF356540CB8"));
    18             Assert.AreEqual(c1, c2);
    19         }
    20     }
    21 }

    测试结果

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

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

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

     1 namespace Wolfy.Shop.Data
     2 {
     3     /// <summary>
     4     /// 描述:nhibernate辅助类
     5     /// 创建人:wolfy
     6     /// 创建时间:2014-10-16
     7     /// </summary>
     8     public class NHibernateHelper
     9     {
    10         private static ISessionFactory _sessionFactory;
    11         private static ISession _session;
    12         private static object _objLock = new object();
    13         private NHibernateHelper()
    14         {
    15 
    16         }
    17         /// <summary>
    18         /// 创建ISessionFactory
    19         /// </summary>
    20         /// <returns></returns>
    21         public static ISessionFactory GetSessionFactory()
    22         {
    23             if (_sessionFactory == null)
    24             {
    25                 lock (_objLock)
    26                 {
    27                     if (_sessionFactory == null)
    28                     {
    29                         //配置ISessionFactory
    30                         _sessionFactory = (new Configuration()).Configure().BuildSessionFactory();
    31                     }
    32                 }
    33             }
    34             return _sessionFactory;
    35 
    36         }
    37         /// <summary>
    38         /// 重置Session
    39         /// </summary>
    40         /// <returns></returns>
    41         public static ISession ResetSession()
    42         {
    43             if (_session.IsOpen)
    44                 _session.Close();
    45             _session = _sessionFactory.OpenSession(); ;
    46             return _session;
    47         }
    48         /// <summary>
    49         /// 打开ISession
    50         /// </summary>
    51         /// <returns></returns>
    52         public static ISession GetSession()
    53         {
    54             _sessionFactory = GetSessionFactory();
    55             if (_session == null)
    56             {
    57                 lock (_objLock)
    58                 {
    59                     if (_session == null)
    60                     {
    61                         _session = _sessionFactory.OpenSession();
    62                     }
    63                 }
    64             }
    65             return _session;
    66         }
    67     }
    68 
    69 }

    修改GetCustomerById方法

     1         /// <summary>
     2         /// 根据客户id查询
     3         /// </summary>
     4         /// <param name="customerID"></param>
     5         /// <returns></returns>
     6         public Customer GetCustomerById(Guid customerID)
     7         {
     8             ISession session = NHibernateHelper.GetSession();
     9             return session.Get<Customer>(customerID);
    10         }
    11         /// <summary>
    12         /// 根据客户id查询
    13         /// </summary>
    14         /// <param name="customerID"></param>
    15         /// <returns></returns>
    16         public Customer GetCustomerById2(Guid customerID)
    17         {
    18             ISession session = NHibernateHelper.ResetSession();
    19             return session.Get<Customer>(customerID);
    20         }

    单元测试

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

    运行测试,结果

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

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

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

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

     1         /// <summary>
     2         /// 根据客户id查询
     3         /// </summary>
     4         /// <param name="customerID"></param>
     5         /// <returns></returns>
     6         public Customer GetCustomerById(Guid customerID)
     7         {
     8             ISession session = NHibernateHelper.GetSession();
     9             return session.Get<Customer>(customerID);
    10         }
    11         public Customer LoadCustomerById(Guid customerID)
    12         {
    13             ISession session = NHibernateHelper.GetSession();
    14             return session.Load<Customer>(customerID);
    15         }

    单元测试

     1         [TestMethod]
     2         public void GetCustomerByIdTest()
     3         {
     4             Console.WriteLine("----使用Get方式获取Customer实例----");
     5             Customer c1 = _customerData.GetCustomerById(new Guid("DDF63750-3307-461B-B96A-7FF356540CB8"));
     6             Assert.IsNotNull(c1);
     7             Console.WriteLine("输出该客户的id信息:");
     8             Console.WriteLine(c1.CustomerID);
     9             Assert.AreEqual(c1.CustomerID.ToString().ToUpper(), "DDF63750-3307-461B-B96A-7FF356540CB8");
    10             Console.WriteLine("输出该客户的名字:");
    11             Console.WriteLine(c1.NameAddress.CustomerName);
    12             Assert.AreEqual(c1.NameAddress.CustomerName,"wolfy");
    13         }
    14         [TestMethod]
    15         public void LoadCustomerByIdTest()
    16         {
    17             Console.WriteLine("----使用Load方式获取Customer实例----");
    18             Customer c1 = _customerData.LoadCustomerById(new Guid("DDF63750-3307-461B-B96A-7FF356540CB8"));
    19             Assert.IsNotNull(c1);
    20             Console.WriteLine("输出该客户的id信息:");
    21             Console.WriteLine(c1.CustomerID);
    22             Assert.AreEqual(c1.CustomerID.ToString().ToUpper(), "DDF63750-3307-461B-B96A-7FF356540CB8");
    23             Console.WriteLine("输出该客户的名字:");
    24             Console.WriteLine(c1.NameAddress.CustomerName);
    25             Assert.AreEqual(c1.NameAddress.CustomerName, "wolfy");
    26         }

    运行单元测试,查看结果

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

    一级缓存管理

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

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

    ISession.Clear():清空缓存。

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

    在CustomerData中添加方法

     1       /// <summary>
     2         /// 清除session中的缓存
     3         /// </summary>
     4         public void ClearCache()
     5         {
     6             ISession session = NHibernateHelper.GetSession();
     7             session.Clear();
     8         }
     9         /// <summary>
    10         /// 从缓存中移除某个对象
    11         /// </summary>
    12         /// <param name="customer"></param>
    13         /// <returns></returns>
    14         public void RemoveCustomerFromCache(Customer customer)
    15         {
    16             ISession session = NHibernateHelper.GetSession();
    17             session.Evict(customer);
    18         }
     1    /// <summary>
     2         /// session是否包含customer对象
     3         /// </summary>
     4         /// <param name="customer"></param>
     5         /// <returns></returns>
     6         public bool IsContains(Customer customer)
     7         {
     8             ISession session = NHibernateHelper.GetSession();
     9             return session.Contains(customer);
    10         }

    单元测试方法

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

    测试结果

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

    总结

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

    参考文章

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

  • 相关阅读:
    nginx内置变量
    MySQL获取错误编号 try判断 获取 Exception 上的错误
    MySQL错误代码大全(转)
    PHP递归菜单/权限目录(无限极数组)
    PHP魔术方法
    php and和&&的一个坑(文章是发现其他博客,保存自己笔记)
    nginx配置php与前后端分离(文档只供本人观看,接受错误但勿喷!)
    servlet的构造器与init方法
    模板方法设计模式
    MVC
  • 原文地址:https://www.cnblogs.com/wolf-sun/p/4130497.html
Copyright © 2011-2022 走看看