一级缓存
为了获得更好的性能,NHibernate智能地缓存数据。NHibernate有不同的缓存机制起作用,最重要的就是一级缓存。sess每个ion对象维持一个一级缓存,session对象创建时缓存创建,session对象释放时缓存销毁。
缓存只不过是一个哈希表。哈希表根据唯一键存储值,值可以根据唯一键检索。
一个实体由它的ID唯一标识,如果两个实体类型相同,ID也相等,那么这两个实体是相等的。NHibernate要求两个相同类型的对象不能有相同的ID。原因是,如果允许系统有相同ID的两个实例,那么就会将系统置于不一致的状态中。有了这个条件,NHibernate就可以执行下面的操作了:
NHibernate session对象从数据库中加载指定ID的实体,然后放到一级缓存中,访问该实体的键是它的ID值。当系统再次从数据库中加载同一个实体时,session对象首先检查它的缓存,如果实体已经存在于缓存中,NHibernate就返回缓存的实例。只有实体不在缓存时,NHibernate session对象才从数据库中加载实体。看下面的过程:
A步骤:
- 程序请求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,并返回给程序
证明:
从上面执行结果可以得出结论:
session.Get<EmployeeInfo>(1);一共获取数据为a b c d四次,但实际操作数据库存仅为一次,从而证明了上述的A步骤 正确性:
从第二步可以证明:最重要的就是一级缓存。每个session对象维持一个一级缓存,session对象创建时缓存创建,session对象释放时缓存销毁。
二级缓存
我们已经看到NHibernate提供了非常有效的方式缓存数据。可惜,一级缓存绑定到session对象,也就是说每次session被释放,所有的缓存数据就会丢失。二级缓存定义在session工厂级别的,只要session工厂没有被释放缓存就一直存在。一旦实体加载,二级缓存就被激活,实体对所有的session(同session工厂的)都可用。这样,只要实体在二级缓存中,NHibernate就不会从数据库加载实体,直到它从缓存中移除。
测试代码验证:
1 public static void TextSecondCache() 2 { 3 ISessionFactory sessionFactory = CreateISessionFactoryByXml(); 4 Console.WriteLine("第一个session开始"); 5 using (ISession session = sessionFactory.OpenSession()) 6 { 7 EmployeeInfo a = session.Get<EmployeeInfo>(1); 8 Console.WriteLine("a " + a.EmpName); 9 10 } 11 12 Console.WriteLine("第一个session结束 第2个session开始"); 13 using (ISession session = sessionFactory.OpenSession()) 14 { 15 EmployeeInfo a = session.Get<EmployeeInfo>(1); 16 Console.WriteLine("a " + a.EmpName); 17 } 18 19 }
没有开启二级缓存执行情况: 一共执行了二次SQL
开启二级缓存的情况
第一次执行:只执行了一次SQL操作
第二次执行:没有执行SQL,直接在SQL中获取查询对象