NHibernate 二级缓存实现






4.85/5 (30投票s)
在本文中,我将逐步解释 NHibernate 二级缓存的实现方法。
目录
1. 引言
在本文中,我将解释 NHibernate 二级缓存是如何实现的。作为一个对象关系映射器 (ORM),在使用 NHibernate 时,我们经常会看到开发者尝试使用 NHibernate 的缓存功能来提高性能。在本文中,我将重点介绍二级缓存发挥作用以提升性能的方面。二级缓存将有助于克服一级缓存的限制。任何有兴趣了解如何在任何项目中实现二级缓存的人,本文也适合他们。
2. 先决条件
- NHibernate 基础知识
- 一级缓存
3. 背景
实体级别的缓存是一项非常重要的技术,可以提高应用程序的性能。有时,我们在分层架构中引入一个缓存层,该层正好位于数据访问层之前。该层的主要职责是缓存业务对象,并在业务层需要时从其缓存中提供业务实体。
有时,我们使用 ASP.NET Web 组件将实体缓存到 Web 上下文中,例如:
- ViewState,
- Session,
- Application,
- Cache object
当有人使用 NHibernate 及其二级缓存功能时,就无需再缓存其他层的实体了。NHibernate 提供了各种缓存和过期策略。我将尝试以非常简单的方式解释,以便任何人都能轻松地在他们的应用程序中使用它。
4. 先决组件
如果有人想在他的应用程序中使用 NHibernet,那么需要几个组件,并且应该将这些组件作为引用添加到他的项目中。组件是:
-
NHibernate
-
Lesi.Collections
如果您倾向于使用 Fluent 配置(我更喜欢 Fluent 映射配置而不是 XML 映射配置),那么您可以引用另一个
FluentNHibernate
这些是 NHibernate 的核心组件。
5. 二级缓存提供程序
如果我想使用二级缓存功能,首先需要将至少一个二级缓存提供程序的引用添加到我的项目中。
市面上有许多缓存提供程序。一些流行的提供程序是:
MemCache
速度
SysCache
SysCache2
Hash Table
Install-Package NHibernate.Caches.SysCache2
Visual Studio 的包管理器窗口中的 cmdlet。它将下载/添加 syscache2 程序集到您的项目中。
请注意,它不会添加 `FluentNHibernate` 组件的引用。您需要手动添加。
6. 配置
添加组件引用后,您需要配置您的
- 数据库和
- 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)。
过程是:
AspNet_SqlCachePollingStoredProcedure
AspNet_SqlCacheRegisterTableStoredProcedure
AspNet_SqlCacheUpdateChangeIdStoredProcedure
AspNet_SqlCacheUnRegisterTableStoredProcedure
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),您需要在 `
<configSections> <section name="syscache2" type="NHibernate.Caches.SysCache2.SysCacheSection, NHibernate.Caches.SysCache2" requirePermission="false"/> </configSections>
然后,您需要在 `
<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` 实际上是一个独立的缓存过期策略。从我们的实体映射配置中,我们可以引用该策略。`
另一个 `
<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 二级缓存是一项非常独特的功能,它能够提高应用程序的性能。需要注意的是,它是一种类似于其他缓存的缓存技术。在应用它之前,您必须仔细考虑并计划哪些实体需要支持二级缓存,并定义其过期策略。如果您在选择要缓存的实体及其最佳过期策略时犯了错误,那么它将不会提供任何好处,而且可能会导致许多错误。因此,在计划/配置您的实体以利用二级缓存的优势之前,花时间重新思考、修订、验证并与您的团队成员共享,以便在您的计划/配置/实体选择缓存方面不会出现任何错误。