NHibernate 缓存

NHibernate 缓存NHibernate支持两种级别的缓存,即一级缓存以及二级缓存。一级缓存一级缓存就是ISession缓存,在ISession的生命周期内可用,多个ISession之间不能共享缓存的对象,通过ISessionFactory创建的ISession默认支持一级缓存,不需要特殊的配置。在NHibernate的参考文档中,对ISession的描述如下:

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

NHibernate 支持两种级别的缓存, 即一级缓存以及二级缓存。

一级缓存

一级缓存就是 ISession 缓存, 在 ISession 的生命周期内可用, 多个 ISession 之间不能共享缓存的对象, 通过 ISessionFactory 创建的 ISession 默认支持一级缓存, 不需要特殊的配置。 在 NHibernate 的参考文档中, 对 ISession 的描述如下:

A single-threaded, short-lived object representing a conversation between the application and the persistent store. Wraps an ADO.NET connection. Factory for ITransaction. Holds a mandatory (first-level) cache of persistent objects, used when navigating the object graph or looking up objects by identifier. looking up objects by identifier.

注意最后一句, 明确说明了一级缓存的用途:

  • 在对象树种导航、浏览时, 使用一级缓存;
  • 根据对象的 id 加载对象;

由此可以看出, 一级缓存的作用是比较有限的, 但是也有用得着的地方。

一级缓存测试

一级缓存缓存无需配置, 默认支持, 因此, 在使用 session 查询对象, 如果仅仅是根据 id 加载指定的对象, 需要使用 session 的 Get 或 Load 方法, 这样可以充分利用 session 的一级缓存, 下面是一些测试用例以及输出:

1、测试一级缓存

[Test]
public void TestSessionLoad() {
    using (var session = this._sessionFactory.OpenSession()) {
        Console.WriteLine("Before Load Category");
        var cat = session.Get<Category>(1);
        Console.WriteLine("{0}, {1}", cat.CategoryID, cat.CategoryName);
        cat = session.Get<Category>(1);
        Console.WriteLine("{0}, {1}", cat.CategoryID, cat.CategoryName);
    }
}

在上面的测试中, 两次加载同一个实体类, 该测试的输出为:

First get category 1
NHibernate: 
    SELECT
        category0_.[CategoryID] as column1_0_0_,
        category0_.[CategoryName] as column2_0_0_,
        category0_.[Description] as column3_0_0_,
        category0_.[Picture] as column4_0_0_ 
    FROM
        [dbo].[Categories] category0_ 
    WHERE
        category0_.[CategoryID]=@p0;
    @p0 = 1 [Type: Int32 (0)]
1, Beverages
second get category 1
1, Beverages

从输出可以看到, 只有第一次调用 Get 方法加载实体类时, 有 sql 输出, 从数据库取出了数据, 第二次加载则没有 sql 数据, 也就是利用了 session 的一级缓存。

2、测试 Get 与 Load 方法

session 提供了 Get 和 Load 两个方法, 这两个方法有什么区别呢? 我的测试代码如下:

[Test]
public void TestSessionGet() {
    using (var session = this._sessionFactory.OpenSession()) {
        Console.WriteLine("Before Get Category");
        var cat = session.Get<Category>(1);
        Console.WriteLine("After Get Category");
    }
}

对应的输出代码如下:

Before Get Category
NHibernate: 
    SELECT
        category0_.[CategoryID] as column1_0_0_,
        category0_.[CategoryName] as column2_0_0_,
        category0_.[Description] as column3_0_0_,
        category0_.[Picture] as column4_0_0_ 
    FROM
        [dbo].[Categories] category0_ 
    WHERE
        category0_.[CategoryID]=@p0;
    @p0 = 1 [Type: Int32 (0)]
After Get Category

从输出可以看到, 调用 Get 方法之后, Nh 立刻从数据库加载实例, 接下来看对 Load 方法的测试:

[Test]
public void TestSessionLoad() {
    using (var session = this._sessionFactory.OpenSession()) {
        Console.WriteLine("Before Load Category");
        var cat = session.Load<Category>(1);
        Console.WriteLine("After Load Category");
        Console.WriteLine("{0}, {1}", cat.CategoryID, cat.CategoryName);
    }
}

对应的输出代码为:

Before Load Category
After Load Category
NHibernate: 
    SELECT
        category0_.[CategoryID] as column1_0_0_,
        category0_.[CategoryName] as column2_0_0_,
        category0_.[Description] as column3_0_0_,
        category0_.[Picture] as column4_0_0_ 
    FROM
        [dbo].[Categories] category0_ 
    WHERE
        category0_.[CategoryID]=@p0;
    @p0 = 1 [Type: Int32 (0)]
1, Beverages

可以看出, 调用完 Load 方法之后, nh 并没有立即从数据库加载实体, 而是等到读取实体类属性时, 才从数据库加载, 也就是说, Load 方法是延迟加载的。

测试Query

根据文档的描述, 用 session 查询对象, 应该是不能利用一级缓存的, 我们来测试一下:

[Test]
public void TestSessionLambdaQuery() {
    using (var session = this._sessionFactory.OpenSession()) {
        (from c in session.Query<Category>()
            where c.CategoryID == 1
            select c).First();

        (from c in session.Query<Category>()
            where c.CategoryID == 1
            select c).First();
    }
}

该测试用例的输出如下:

NHibernate: 
    select
        TOP (1)  category0_.[CategoryID] as column1_0_,
        category0_.[CategoryName] as column2_0_,
        category0_.[Description] as column3_0_,
        category0_.[Picture] as column4_0_ 
    from
        [dbo].[Categories] category0_ 
    where
        category0_.[CategoryID]=@p0;
    @p0 = 1 [Type: Int32 (0)]
NHibernate: 
    select
        TOP (1)  category0_.[CategoryID] as column1_0_,
        category0_.[CategoryName] as column2_0_,
        category0_.[Description] as column3_0_,
        category0_.[Picture] as column4_0_ 
    from
        [dbo].[Categories] category0_ 
    where
        category0_.[CategoryID]=@p0;
    @p0 = 1 [Type: Int32 (0)]

从输出可以看出, 用 session 查询对象, 确实不能利用一级缓存。

注意: 如果查询时不想使用一级缓存, 可以 StatelessSession 对象, 和 Session 对象用法一样, 只是该对象没有一级缓存。

一级缓存管理

一级缓存的管理也是很简单的, 可以通过下面的三个方法管理:

  • session.Evict 从一级缓存中删除指定的实例;
  • session.Clear 清空一级缓存, 不会保存修改的内容;
  • session.Contains 检查实例是否存在于一级缓存中。

二级缓存

二级缓存是 SessionFactory 级别的缓存, 也就是数据库级别的缓存, 可以被同一个 SessionFactory 创建的所有 session 共享。

启用二级缓存

Nh 默认未启用二级缓存, 启用二级缓存需要如下步骤:

1、 在 hibernate.cfg.xml 文件中添加下面三个属性:

<property name="cache.provider_class">NHibernate.Cache.HashtableCacheProvider</property>`  
<property name="cache.use_second_level_cache">true</property>`  
<property name="cache.use_query_cache">true</property>`

这三个属性的作用是显而易见的, 第一个是指定使用什么二级缓存的实现, 第二个是启用二级缓存, 第三个是为查询启用二级缓存缓存。

NHibernate 的二级缓存是可以扩展的, NHibernate.ControlLib 提供了几个实现, 分别适用于不同的场景:

  • NHibernate.Caches.MemCache
  • NHibernate.Caches.Prevalence
  • NHibernate.Caches.SharedCache
  • NHibernate.Caches.SysCache
  • NHibernate.Caches.SysCache2
  • NHibernate.Caches.Velocity

这些实现都是

2、 配置指定的实体类、集合启用二级缓存缓存

在 hibernate.cfg.xml 文件中添加下面的设置:

<class-cache class="HibernateTest.Models.Category" usage="read-only" include="all"/>

这一句表示对实体类 HibernateTest.Models.Category 启用二级缓存, 在实际项目中, 可以根据需要对多个实体类启用二级缓存。 也可以在实体类的 hbm 映射文件中配置使用二级缓存, 不过在 hibernate.cfg.xml 文件中统一配置是推荐的做法。

二级缓存测试

二级缓存的几个测试用例如下:

1、 测试 Get 方法:

[Test]
public void TestGetEntity() {
    using (var session = this._sessionFactory.OpenSession()) {
        session.Get<Category>(1);
    }
    using (var session = this._sessionFactory.OpenSession()) {
        session.Get<Category>(1);
    }
}

对应的输出为:

NHibernate: 
    SELECT
        category0_.[CategoryID] as column1_0_0_,
        category0_.[CategoryName] as column2_0_0_,
        category0_.[Description] as column3_0_0_,
        category0_.[Picture] as column4_0_0_ 
    FROM
        [dbo].[Categories] category0_ 
    WHERE
        category0_.[CategoryID]=@p0;
    @p0 = 1 [Type: Int32 (0)]

从测试用例的输出可以看出, 二级缓存时可以在不同的 session 之间共享。

2、 测试 HQL 查询:

[Test]
public void TestHqlQuery() {
    using (var session = this._sessionFactory.OpenSession()) {
        var query = session.CreateQuery("from Category")
            .SetCacheMode(CacheMode.Normal)
            .SetCacheRegion("AllCategories")
            .SetCacheable(true);
        query.List<Category>();
    }
    using (var session = this._sessionFactory.OpenSession()) {
        var query = session.CreateQuery("from Category")
            .SetCacheMode(CacheMode.Normal)
            .SetCacheRegion("AllCategories")
            .SetCacheable(true);
        query.List<Category>();
    }
}

对应的输出为:

NHibernate: 
    select
        category0_.[CategoryID] as column1_0_,
        category0_.[CategoryName] as column2_0_,
        category0_.[Description] as column3_0_,
        category0_.[Picture] as column4_0_ 
    from
        [dbo].[Categories] category0_

3、 测试 Linq 查询:

[Test]
public void TestLinqQuery() {
    using (var session = this._sessionFactory.OpenSession()) {
        var query = session.Query<Category>()
            .Cacheable()
            .CacheMode(CacheMode.Normal)
            .CacheRegion("AllCategories");
        var result = query.ToList();
    }
    using (var session = this._sessionFactory.OpenSession()) {
        var query = session.Query<Category>()
            .Cacheable()
            .CacheMode(CacheMode.Normal)
            .CacheRegion("AllCategories");
        var result = query.ToList();
    }
}

对应的输出为:

NHibernate: 
    select
        category0_.[CategoryID] as column1_0_,
        category0_.[CategoryName] as column2_0_,
        category0_.[Description] as column3_0_,
        category0_.[Picture] as column4_0_ 
    from
        [dbo].[Categories] category0_

4、 测试 QueryOver 查询:

[Test]
public void TestQueryOver() {
    using (var session = this._sessionFactory.OpenSession()) {
        var query = session.QueryOver<Category>()
            .Cacheable()
            .CacheMode(CacheMode.Normal)
            .CacheRegion("AllCategories");
        query.List();
    }
    using (var session = this._sessionFactory.OpenSession()) {
        var query = session.QueryOver<Category>()
            .Cacheable()
            .CacheMode(CacheMode.Normal)
            .CacheRegion("AllCategories");
        query.List();
    }
}

对应的输出为:

NHibernate: 
    SELECT
        this_.[CategoryID] as column1_0_0_,
        this_.[CategoryName] as column2_0_0_,
        this_.[Description] as column3_0_0_,
        this_.[Picture] as column4_0_0_ 
    FROM
        [dbo].[Categories] this_

二级缓存选项

NHibernate 二级有几个配置选项, 他们分别是:

实体类以及集合二级缓存配置选项

指定类:

<class-cache class="类名称" region="默认类名称" include="all|non-lazy"
         usage="read-only|read-write|nonstrict-read-write|transactional" />

指定集合:

<collection-cache collection ="集合名称" region="默认集合名称"
              usage="read-only|read-write|nonstrict-read-write|transactional"/>
  • region:可选,默认值为类或集合的名称,用来指定二级缓存的区域名,对应于缓存实现的一个命名缓存区域。
  • include:可选,默认值为all,当取non-lazy时设置延迟加载的持久化实例的属性不被缓存。
  • usage:声明缓存同步策略,就是上面说明的四种缓存策略。

查询二级缓存配置

  • Cacheable 为一个查询显示启用二级缓存;
  • CacheMode 缓存模式, 有如下可选:
    1. Ignore:更新数据时将二级缓存失效,其它时间不和二级缓存交互
    2. Put:向二级缓存写数据,但不从二级缓存读数据
    3. Get:从二级缓存读数据,仅在数据更新时向二级缓存写数据
    4. Normal:默认方式。从二级缓存读/写数据
    5. Refresh:向二级缓存写数据,想不从二级缓存读数据,通过在配置文件设置cache.use_minimal_puts从数据库中读取数据时,强制二级缓存刷新
  • CacheRegion 给查询缓存指定了特定的命名缓存区域, 如果两个查询相同, 但是指定的 CacheRegion 不同, 则也会从数据库查询数据。

以上是在项目中用到的二级缓存相关知识的整理, 肯定不完整, NHibernate 的缓存还有更多的地方需要挖掘。

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/158253.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • ov7725摄像头–图像中间亮四周暗[通俗易懂]

    ov7725摄像头–图像中间亮四周暗[通俗易懂]使用OV7725摄像头采集图像进行商品识别,uvc调试过程中发现图像中间亮四周暗;网上找原因,说是lens的CRA和sensor的CRA不匹配;可以通过矫正透镜改进;查看手册,lenscorrection部分;果然有这部分介绍12 DealwithLens—处理Lens12.1 Lightfalloff—-光线脱落光线掉落意味着图像的角落比图像的中心更暗。它是由镜头引起的…

  • uni-app的unipush实现通知栏推送服务全过程「建议收藏」

    uni-app的unipush实现通知栏推送服务全过程「建议收藏」背景说明文档这个事情官方应该提供出来,可惜官方觉得是多余的,免费的东西凭啥给你做好。于是我在这里叙述一下实现消息通知推送的步骤。uni-app官方文档入口https://uniapp.dcloud.io/api/plugins/pushuniPush官方使用指南https://ask.dcloud.net.cn/article/35622推送H5+API接口:https://www….

  • idea maven设置本地仓库_maven更新本地仓库

    idea maven设置本地仓库_maven更新本地仓库1.file->settings2.在(1)选择Maven,在(2)加入本地Maven位置,在(3)加入到本地settings.xml下,在(4)下添加本地仓库,默认在c盘,更改本地仓库请移步3.完毕

  • bzero 和memset的区别[通俗易懂]

    bzero 和memset的区别[通俗易懂]bzero  原型:externvoidbzero(void*s,intn);  用法:#include  功能:置字节字符串s的前n个字节为零且包括‘\0’。  说明:bzero无返回值,并且使用strings.h头文件,strings.h曾经是posix标准的一部分,但是在POSIX.1-2001标准里面,这些函数被标记为了遗留函数而不推荐使用。在P

    2022年10月13日
  • 关于File类概念及方法的一些介绍

    关于File类概念及方法的一些介绍java.io.File类是文件和目录路径名的抽象表示,主要用于文件和目录的创建、查找和删除等操作。Java把电脑中的文件和文件夹(目录)封装为一个File类,我们可以使用File类对文件和文件夹进行操作。File类的方法可以实现:1.创建一个文件/文件夹2.删除文件/文件夹3.获取文件/文件夹4.判断文件/文件夹是否存在5.对文件夹进行遍历6.获取文件的大小File类是一个与系统无关的类,任何操作系统都可以使用这个类中的方法重点:File:文件;Directory:文件夹/目录

  • QFile源码学习笔记

    QFile源码学习笔记之前简单介绍了Qt读写文件Qt之读写文件http://blog.csdn.net/zhuyunfei/article/details/51249378这里记录下自己学习QFile的笔记。1.在Qt之读写文件中,在打开模式中指定未Append模式,发现如果文件不存在会自动创建新文件,在QFile的源码中找到了原因,在open函数的定义中都有如下语句if(mode&Append)mode

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号