文档目录

本节内容:

简介

ABP提供了一个缓存接口,它内部使用了这个缓存接口。虽然接口的默认实现是MemoryCache,但可以用任何其它实现的缓存供应器。Abp.RedisCache包用Redis实现了缓存(查看下方的“Redis 缓存集成”)。

ICacheManager

缓存的主要接口是ICacheManager。我们可以注入它并用它获取一个缓存,如:

public class TestAppService : ApplicationService
{
private readonly ICacheManager _cacheManager; public TestAppService(ICacheManager cacheManager)
{
_cacheManager = cacheManager;
} public Item GetItem(int id)
{
//Try to get from cache
return _cacheManager
.GetCache("MyCache")
.Get(id.ToString(), () => GetFromDatabase(id)) as Item;
} public Item GetFromDatabase(int id)
{
//... retrieve item from database
}
}

在此例里,我们注入了ICacheManager,并获得一个名为MyCache的缓存。

警告:GetCache方法

如果你的类不是单例,不要在你构造器里使用GetCache,否则可能会销毁你的缓存。

ICache

ICacheManager.GetCache方法返回一个ICache。一个缓存是单例的(每个缓存名)。第一次请求时创建,然后一直返回同一个缓存对象。所以,我们可以在不同的类(客户端)里用相同的名字共享同一个缓存。

在示例代码里,我们看到了ICache.get方法的简单使用。它有两个参数:

key:字符串,必需,一个缓存项的键。

factory:一个action(行为),在找不到指定key的缓存项时调用,Factory方法应该创建并返回切实的项,如果指定key的缓存已存在,就不调用。

ICache接口也有如GetOrDefault、Set、Remove和Clear等方法。同样也有async版本。

ITypedCache

ICache接口以字符串为key,值是object类型。ITypedCache包装了ICache并提供了类型安全、泛型。我们可用泛型的GetCache扩展方法,获取一个ITypedCache:

ITypedCache<int, Item> myCache = _cacheManager.GetCache<int, Item>("MyCache");

同样,我们也可用AsTyped扩展方法,把一个已存在的ICache实例转换成ITypedCache。

配置

默认缓存超时是60分钟,它可以改。如果你超过60分钟没有使用缓存中的项,会从缓存中自动移除。你可以配置指定的缓存或是全部的缓存。

//Configuration for all caches
Configuration.Caching.ConfigureAll(cache =>
{
cache.DefaultSlidingExpireTime = TimeSpan.FromHours();
}); //Configuration for a specific cache
Configuration.Caching.Configure("MyCache", cache =>
{
cache.DefaultSlidingExpireTime = TimeSpan.FromHours();
});

这段代码应该写在你模块的PreInitialize方法里,用这段代码,MyCache将有8个小时的超时时间,其它的缓存有2个小时。

在第一次创建缓存(在第一次请求)调用你的配置行为。配置不是只有DefaultSlidingExpireTime,由于缓存对象是一个ICache,所以你可以用它的属性和方法,自由的配置和初始化。

实体缓存

虽然ABP缓存系统出于普通的目的,但有一个EntityCache基类,可帮你缓存实体。如果我们通过它们的Id获取的实体,我们可以用这个基类缓存它们,就不用再频繁地从数据库查询。假设我们有如下所示的一个person实体:

public class Person : Entity
{
public string Name { get; set; } public int Age { get; set; }
}

并假设我们已经知道Id,要频繁地获取Name。首先,我们需要创建一个类来缓存项:

[AutoMapFrom(typeof(Person))]
public class PersonCacheItem
{
public string Name { get; set; }
}

我们不应该直接在缓存里存储实体,由于缓存可能需要序列化缓存对象,而实体不一定能序列化(尤其有导航属性的实体)。这就是为什么我们创建一个简单(像DTO:数据传输对象)类存储数据。添加AutoMapFrom特性,它可以自动地把Person转换成PersonCacheItem对象。如果我们不使用AutoMapFrom,我们应该为重载EntityCache类的MapToCacheItem方法,手动转换/映射。

虽然不是必需,但我们可能想为我们的缓存类定义一个接口:

public interface IPersonCache : IEntityCache<PersonCacheItem>
{ }

最后,我们可以为实体创建缓存类:

public class PersonCache : EntityCache<Person, PersonCacheItem>, IPersonCache, ITransientDependency
{
public PersonCache(ICacheManager cacheManager, IRepository<Person> repository)
: base(cacheManager, repository)
{ }
}

这就是全部代码,我们的Person缓存已经可用。缓存类可以是暂时的(如示例)或单体的,这不是说缓存的数据是暂时的,它始终在你的应用里是全局的并线程安全的。

现在,任何需要Person的Name时,我们可以通过person的Id从缓存获取,使用Person缓存的示例如下:

public class MyPersonService : ITransientDependency
{
private readonly IPersonCache _personCache; public MyPersonService(IPersonCache personCache)
{
_personCache = personCache;
} public string GetPersonNameById(int id)
{
return _personCache[id].Name; //alternative: _personCache.Get(id).Name;
}
}

我们简单地注入IPersonCache,获取缓存项和获取Name属性。

EntityCache 是如何工作

  • 在第一个调用里获取从仓储(从数据库)获取实体,然后在接下来的调用里从缓存里获取。
  • 如果实体更新或删除后,它自动使缓存失效,所以它将在下一个调用里重新从数据库获取。
  • 使用IObjectMapper映射到缓存项,AutoMpper模块实现了IObjectMapper,所以需要AutoMapper模块。你可以重载MapToCacheItem方法,手动映射实体到缓存项。
  • 使用缓存类全名作为缓存时的名称,你可以通过传递一个缓存名给基构造器来改变它。
  • 是线程安全的。

如果你需要更复杂的缓存技术,你可以扩展EntityCache或创建你自己的解决方案。

Redis 缓存集成

默认缓存管理使用的是内存缓存。所以,如果你有多个并发的Web服务器使用同个应用,可能会成为一个问题,在这种情况下,你需要一个分布/集中缓存服务,你就可以简单的使用Redis做为你的缓存服务器。

首先,你要在你的应用里,安装Abp.RedisCache的Nuget包(例如,你可在你的Web项目里安装)。接着为AbpRedisCacheModule添加DependsOn特性,然后在你模块预初始化方法里调用useRedis扩展方法。如下所示:

//...other namespaces
using Abp.Runtime.Caching.Redis; namespace MyProject.AbpZeroTemplate.Web
{
[DependsOn(
//...other module dependencies
typeof(AbpRedisCacheModule))]
public class MyProjectWebModule : AbpModule
{
public override void PreInitialize()
{
//...other configurations Configuration.Caching.UseRedis();
} //...other code
}
}

Abp.RedisCache包使用”localhost“作为默认连接字符串,你可以在配置文件里添加连接字符串重写它,例如:

<add name="Abp.Redis.Cache" connectionString="localhost"/>

同样,你可以向appSettings里添加Redis的数据库Id,例如:

<add key="Abp.Redis.Cache.DatabaseId" value=""/>

不同的数据库Id,在同一服务器上,帮助创建不同的键空间(独立缓存)。

UseRedis方法也有一个重载,用给定的action(行为)直接设置选项值(在配置文件中重写)。

查看更多有关Redis信息及它的配置,请查阅Redis文档

提醒:Redis服务器应该安装和运行在ABP里。

最新文章

  1. 如何使用yum 下载 一个 package ?如何使用 yum install package 但是保留 rpm 格式的 package ? 或者又 如何通过yum 中已经安装的package 导出它,即yum导出rpm?
  2. ApexSQLLog可以只读取ldf文件
  3. Mongodb3.0.6副本集+分片学习笔记
  4. NGUI之UIRoot
  5. Face The Right Way---hdu3276(开关问题)
  6. KVO的内部实现原理
  7. [转]LUA 学习笔记
  8. 初始化ArrayList的两种方法
  9. 【HDOJ】5657 CA Loves Math
  10. SQLSERVER 检查字段值域并输出行数和值列表
  11. Btrace是一个实时监控工具
  12. Linq 中的distinct去重
  13. 从JavaScript的移位运算看数字在计算机内部的编码——补码
  14. (原)Microsoft Source Reader的简单使用
  15. volatile解析(转)
  16. Spring Quartz定时器 配置文件详解
  17. windows基于vs2017的opencv安装
  18. bat无故报错打印混乱的解决
  19. for 练习
  20. BootStap学习笔记(2)

热门文章

  1. 微信公众号开发之VS远程调试
  2. 菜鸟学Struts2——Actions
  3. SignalR快速入门 ~ 仿QQ即时聊天,消息推送,单聊,群聊,多群公聊(基础=》提升)
  4. iOS开发之App间账号共享与SDK封装
  5. nodejs项目mysql使用sequelize支持存储emoji
  6. 【Machine Learning】决策树案例:基于python的商品购买能力预测系统
  7. C++随笔:从Hello World 探秘CoreCLR的内部(1)
  8. &quot;NHibernate.Exceptions.GenericADOException: could not load an entity&quot; 解决方案
  9. 微信小程序二维码推广统计
  10. jira的插件开发流程实践