65.9K
CodeProject 正在变化。 阅读更多。
Home

NHibernate 二级缓存实现

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.85/5 (30投票s)

2013年1月17日

CPOL

7分钟阅读

viewsIcon

110759

downloadIcon

815

在本文中,我将逐步解释 NHibernate 二级缓存的实现方法。

目录

1. 引言

intro

在本文中,我将解释 NHibernate 二级缓存是如何实现的。作为一个对象关系映射器 (ORM),在使用 NHibernate 时,我们经常会看到开发者尝试使用 NHibernate 的缓存功能来提高性能。在本文中,我将重点介绍二级缓存发挥作用以提升性能的方面。二级缓存将有助于克服一级缓存的限制。任何有兴趣了解如何在任何项目中实现二级缓存的人,本文也适合他们。

2. 先决条件

  • NHibernate 基础知识
  • 一级缓存

3. 背景

实体级别的缓存是一项非常重要的技术,可以提高应用程序的性能。有时,我们在分层架构中引入一个缓存层,该层正好位于数据访问层之前。该层的主要职责是缓存业务对象,并在业务层需要时从其缓存中提供业务实体。

CacheLayer

有时,我们使用 ASP.NET Web 组件将实体缓存到 Web 上下文中,例如:

  • ViewState,
  • Session,
  • Application,
  • Cache object

当有人使用 NHibernate 及其二级缓存功能时,就无需再缓存其他层的实体了。NHibernate 提供了各种缓存和过期策略。我将尝试以非常简单的方式解释,以便任何人都能轻松地在他们的应用程序中使用它。

4. 先决组件

如果有人想在他的应用程序中使用 NHibernet,那么需要几个组件,并且应该将这些组件作为引用添加到他的项目中。组件是:

  1. NHibernate
  2. Lesi.Collections

如果您倾向于使用 Fluent 配置(我更喜欢 Fluent 映射配置而不是 XML 映射配置),那么您可以引用另一个

  1. FluentNHibernate

这些是 NHibernate 的核心组件。

5. 二级缓存提供程序

如果我想使用二级缓存功能,首先需要将至少一个二级缓存提供程序的引用添加到我的项目中。

市面上有许多缓存提供程序。一些流行的提供程序是:

  • MemCache
  • 速度
  • SysCache
  • SysCache2
  • Hash Table
我更喜欢 `SysCache2`,因为它支持数据库更改通知。如果您的应用程序需要分布式缓存,那么您可以查看 Velocity。要将 `SysCache2` 组件的引用添加到我的项目中,我推荐使用 NuGet 包管理器。您可以使用
Install-Package NHibernate.Caches.SysCache2 

Visual Studio 的包管理器窗口中的 cmdlet。它将下载/添加 syscache2 程序集到您的项目中。

请注意,它不会添加 `FluentNHibernate` 组件的引用。您需要手动添加。

6. 配置

config

添加组件引用后,您需要配置您的

  1. 数据库和
  2. Application

以便它可以完美运行。

6.1. 数据库配置

如果您想使用数据库更改通知服务,那么您需要设置 SQL Server 2005 或更高版本(我在网上找到各种来源说 SqlServer 2000 也支持它,但从未尝试过)。接下来,我们需要启用 SQL Server Service Broker 功能。 TSQL 语句是:

ALTER DATABASE <databasename> SET ENABLE_BROKER; 

请注意,您只能对数据库启用一次 Service Broker 功能。我们也可以随时禁用 Service Broker 功能。 TSQL 语句是:

ALTER DATABASE <databasename> SET DISABLE_BROKER; 

接下来,您需要使用 `aspnet_regsql` 工具。

您需要从 Visual Studio 命令提示符执行命令:

aspnet_regsql  –S <sqlserver instance name> -U <database username> 
-P <database user password> -d <database name> -ed 

如果您从 Visual Studio 命令提示符执行 `aspnet_regsql /?` 命令,您将了解此命令及其选项的详细信息。

如果您先打开 SQL Server Profiler,然后执行上述 T-SQL 语句,您会看到它创建了 `AspNet_SqlCacheTablesForChangeNotification` 表,其中包含 5 个存储过程(SP)。

过程是:

  1. AspNet_SqlCachePollingStoredProcedure
  2. AspNet_SqlCacheRegisterTableStoredProcedure
  3. AspNet_SqlCacheUpdateChangeIdStoredProcedure
  4. AspNet_SqlCacheUnRegisterTableStoredProcedure
  5. AspNet_SqlCacheQueryRegisteredTablesStoredProcedure

它还将创建一个名为 `aspnet_ChangeNotification_ReceiveNotificationsOnlyAccess` 的数据库用户角色。

接下来,您需要注册您想要允许更改通知的表。

命令是:

Aspnet_regsql  –S <sqlserver instance name> -U <database username> 
-P <database user password> -d <database name> -t <tablename> -et <sql cache dependency tables>     

您可以创建一个单一的批处理(.bat)文件,其中包含上面列出的所有必要的命令。这将使您的生活更加轻松。

6.2. 应用程序配置

您可能会认为 NHibernate 二级缓存仅在 Web 上下文中工作。但事实并非如此。您也可以轻松地在控制台、Windows 服务应用程序、Windows 应用程序中使用此功能。

在您的配置文件中(如果是 Web 应用程序,则是 web.config;如果是非 Web 应用程序,则是 app.config),您需要在 `` 节点下注册 `syscache2` 部分。

<configSections>
  <section  name="syscache2" type="NHibernate.Caches.SysCache2.SysCacheSection, 
            NHibernate.Caches.SysCache2" requirePermission="false"/>   
</configSections>   

然后,您需要在 `` 节点下注册 `sqlCacheDependency`。如果您使用 App.config,那么您需要在 `` 节点下添加 `` 节点,并且还要添加对 `System.Web` 组件的引用。`SqlCacheDependency` 对象实际上 resides 在此组件中,它是 .NET Framework 组件。因此,它可以在没有任何 Web 上下文的应用程序中工作。

 <system.web>
    <caching>
      <sqlCacheDependency enabled="true" pollTime="1000">
        <databases>
          <add name="db2" connectionStringName="db"/>         
        </databases>       
      </sqlCacheDependency>     
    </caching>   
  </system.web> 

问: 我们为什么需要注册 `sqlCacheDependency`?

答: 实际上,`syscache2` 根据数据库更改通知来使缓存过期(嗯,不总是,但只有在您将“regions”配置为这样时)。`SqlCacheDependency` 对象实际上是管理这些的,并且 `SysCache2` 使用它。

一个重要的属性是 `pollTime`(以毫秒为单位)。`pollTime` 的值表示它定期访问数据库以检查是否有任何更改的时间间隔。

`SysCache2` 区域在 web/app config 中注册。`` 节点将在 `` 节点下注册。

<syscache2>
    <cacheRegion name="tableDependency" priority="High">
      <dependencies>
        <tables>
          <add name="one" databaseEntryName="db2" tableName="MyTable1" />         
        </tables>       
      </dependencies>      
    </cacheRegion>   
  </syscache2>

您可以看到有一个名为“tableDependency”的“cacheRegion”节点。`CacheRegion` 实际上是一个独立的缓存过期策略。从我们的实体映射配置中,我们可以引用该策略。`` 节点的 `databaseEntryName` 属性引用 `` & `` 节点下的 ``。这个 `databaseEntryName` 属性有时会引起混淆,那就是它的值是什么。所以我们应该仔细设置该值。

另一个 `` 是为在特定时间缓存过期而注册的。

<syscache2>
<cacheRegion name="ExpireAfterCertainTime" timeOfDayExpiration="22:25:00" priority="High"/>
</syscache2>   

上面的区域引用缓存将在晚上 8:00:00 过期。属性值应为 24 小时时间格式。

另一个 `` 是为在特定时间间隔缓存过期而注册的。

<syscache2>
      <cacheRegion name="FiveSecondTimeInterval" relativeExpiration="5" priority="High"/>
</syscache2> 

上面的区域引用缓存将在 5 秒后存储在缓存中。之后,它将自动过期。

7. NHibernate 会话

在 NHibernate 中,我们需要创建一个 `SessionFactory` 类。使用该类,我们可以打开一个新的会话并开始与数据库通信。创建 `SessionFactory` 对象很耗时,因此我们应该将其创建为单例会话。也就是说,每个应用程序上下文只创建一次。 `SessionFactory` 对象创建代码示例:

private static ISessionFactory _sessionFactory;
public static ISessionFactory GetSessionFactory()
{
    //The code is not thread safe.
    if (null == _sessionFactory)
    {
        FluentConfiguration nhConfig = Fluently
            .Configure()
            .Database(MsSqlConfiguration
                .MsSql2008.ConnectionString(c => c
                    .Database(_conn.InitialCatalog)
                    .Server(_conn.DataSource)
                    .Username(_conn.UserID)
                    .Password(_conn.Password)
                )
            )
            .Mappings(m => m.FluentMappings.AddFromAssemblyOf<Developer>()
            .Conventions.Add(DefaultLazy.Never()));
        nhConfig.Cache(c => c.ProviderClass<SysCacheProvider>().UseSecondLevelCache());
        _sessionFactory = nhConfig
            .ExposeConfiguration(v => new SchemaExport(v).Create(false, false))
            .BuildSessionFactory();
    }
    return _sessionFactory;
} 

我们可以像这样创建和打开会话:

public static ISession CreateSession()    
{   ISessionFactory factory = GetSessionFactory(); 
   return factory.OpenSession();         
}   

如果您想通过配置启用/禁用二级缓存,那么您需要使用以下代码创建 `SessionFactory` 对象,而不是使用上面的代码:

public static ISessionFactory GetSessionFactory()
{
    FluentConfigurationnhConfig = Fluently.Configure()
                    .Database(MsSqlConfiguration.MsSql2008.ConnectionString(
                        c => c.Database(conn.InitialCatalog)
                            .Server(conn.DataSource)
                            .Username(conn.UserID).
                            Password(conn.Password)))
                .Mappings(m => m.FluentMappings.AddFromAssemblyOf<Organization>()
                            .Conventions.Add(DefaultLazy.Never()));

    if (Config.IsSecondLevelCachingEnabled)
        nhConfig = nhConfig.Cache(c => c.ProviderClass<SysCacheProvider>()
            .UseSecondLevelCache());

    _sessionFactory = nhConfig.ExposeConfiguration(v => new SchemaExport(v)
        .Create(false, false)).BuildSessionFactory();

    return _sessionFactory;
}

8. 实体映射

如果没有从实体映射类进行缓存配置,则二级缓存将不起作用。所以要小心。

问: 如何从实体映射类配置缓存?

答: 请看下面的代码。这里我使用的是 Fluent 配置。如果您愿意,也可以使用基于 XML 的配置。 `Developer` 类:

 public class Developer 
 { 
        public virtual int Id { get; set; }
        public virtual string FullName { get; set; }
        public virtual Department Department { get; set; }
        public Developer(){}  
 } 

以及 `Developer` 类的 Fluent 映射类:

public class DeveloperMap : ClassMap<Developer>
{
    public DeveloperMap()
    {
        base.Cache.NonStrictReadWrite().Region("FiveSecondTimeInterval");
        //base.Cache.NonStrictReadWrite().Region("ExpireAfterCertainTime");                        //base.Cache.NonStrictReadWrite().Region("tableDependency");
        base.Table("Developers");
        base.Id(c => c.Id).Column("Id");
        base.Map(c => c.FullName).Column("FullName");
        base.References(c => c.Department).Column("DepartmentId");
    }
}  

在上面的代码中,`DeveloperMap` 类的构造函数的第一行声明它需要支持缓存,并根据 `Region` 声明配置其缓存过期策略。支持许多类型的缓存使用模式,例如 `ReadOnly`、`NonStrictReadWrite` 等。如果您在网上搜索,可以找到更多关于这方面的信息。

9. 结论

NHibernate 二级缓存是一项非常独特的功能,它能够提高应用程序的性能。需要注意的是,它是一种类似于其他缓存的缓存技术。在应用它之前,您必须仔细考虑并计划哪些实体需要支持二级缓存,并定义其过期策略。如果您在选择要缓存的实体及其最佳过期策略时犯了错误,那么它将不会提供任何好处,而且可能会导致许多错误。因此,在计划/配置您的实体以利用二级缓存的优势之前,花时间重新思考、修订、验证并与您的团队成员共享,以便在您的计划/配置/实体选择缓存方面不会出现任何错误。

© . All rights reserved.