缓存

介绍

  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的缓存。缓存名称是大小写敏感的,意味着“MyCache”和“MYCACHE”是不同的缓存。

  警告:GetCache方法

  不要在构造函数中使用GetCache。如果类不是单例的话,缓存可能会被释放。

ICache

  ICacheManager.GetCaChe方法返回ICache。缓存是单例的(每个缓存名称)。首次需要的时候创建,然后每次都返回同样的缓存对象。所以,我们可以在不同的类(客户端)使用相同的名字共享同样的缓存。

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

  • Key:缓存中一个项的唯一字符串键。
  • factory:如果指定的键没有项目时调用。工厂方法应该创建并返回真实的项。如果指定的键在缓存中存在的话就不会调用这个方法。

  ICache接口也有如GetOrDefault,Set,Remove和Clear这样的方法。同样也有这些方法的异步版本。

ITypedCache

ICache接口使用string类型作为键,object作为值。ITypeCache是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基类。如果我们通过Ids获取到实体并且想通过Id缓存实体而不是经常从数据库查询,我们就可以使用这个基类。假如我们有一个Person实体,如下:

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

  假如我们知道Id并想以此获取people的Name。首先,我们创建一个类储存缓存项:

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

  不应该直接在缓存中直接存储实体,因为缓存可能需要序列化缓存的对象,实体可能不能被序列化(尤其是有导航属性时)。这就是我们在缓存中定义一个简单类(像DTO)存储数据的原因。因为我们想使用AutoMapper自动将Person实体转换为PersonCahcedItem,所以在类上添加了AutoMapFrom特性。如果我们不使用AutoMapper,那需要重写EntityCache类的MapToCacheItem方法来实现自动转换或映射。

  我们希望定义一个缓存类的接口,虽然这不是必须的:

public interface IPersonCache : IEntityCache<PersonCacheItem>
{ }

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

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

  就这样,我们的person缓存可以使用了。Cache类可以是临时的(如本例)也可以是单例的。这并不意味着缓存数据是临时的。在应用中,它总是全局缓存并且访问是线程安全的。

  现在,不管何时我们需要person的Name时,我们可以通过person`s 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属性。

实体缓存如何工作

  • 在首次调用时,从仓储(从数据库)获取实体。然后在之后的调用从缓存获取。
  • 如果实体被更新或删除,会自动使缓存实体无效。然后,在下次调用时会从数据库中重新获取。
  • 使用IObjectMapper映射实体和缓存项。IObjectMapper通过AutoMapper模块实现。所以,如果使用的话需要AutoMapper模块。可以重写MapToCacheItem方法手动映射实体和缓存项。
  • 使用缓存类FullName作为缓存名称。可以通过向基类构造函数传递缓存名称来改变它。
  • 线程安全。

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

Redis缓存集成

  默认的缓存管理器使用内存缓存。所以,如果有多于一个并发网络服务器运行同样的应用,将会成为一个问题。在这种情况下,需要使用一个分布式/中央缓存服务器。可以很简单的使用Redis作为缓存服务器。

  首先,需要在应用(例如,可以安装在Web工程)中安装Abp.RedisCache nuget包。然后,需要需要给AbpRedisCacheModule添加DependsOn特性,并在模块的PreInitialize方法中调用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=""/>

  在同一个服务器中,不同的数据库ids用来创建不同的关键空间(隔离缓存)。

  UseRedis方法有个重载,可以用来直接设置选项值(在配置文件中重写值)。

  参见Redis文档获取关于Redis及配置的更多信息。

  注意:Redis服务器应该安装并运行,以便在ABP中使用Redis缓存。

返回主目录

ABP官方文档翻译 2.3 缓存的更多相关文章

  1. ABP官方文档翻译 10.1 ABP Nuget包

    ABP Nuget包 Packages Abp Abp.AspNetCore Abp.Web.Common Abp.Web Abp.Web.Mvc Abp.Web.Api Abp.Web.Api.OD ...

  2. 0.0 ABP官方文档翻译目录

    一直想学习ABP,但囿于工作比较忙,没有合适的契机,当然最重要的还是自己懒.不知不觉从毕业到参加工作七年了,没留下点儿什么,总感觉很遗憾,所以今天终于卯足劲鼓起勇气开始写博客.有些事能做的很好,但要跟 ...

  3. ABP官方文档翻译 2.5 设置管理

    设置管理 介绍 关于 ISettingStore 定义设置 设置范围 重写设置定义 获取设置值 服务端 客户端 更改设置 关于缓存 介绍 每个应用都需要存储设置,并且在应用的某些地方需要使用这些设置. ...

  4. ABP官方文档翻译 6.2.1 ASP.NET Core集成

    ASP.NET Core 介绍 迁移到ASP.NET Core? 启动模板 配置 启动类 模块配置 控制器 应用服务作为控制器 过滤器 授权过滤器 审计Action过滤器 校验过滤器 工作单元Acti ...

  5. ABP官方文档翻译 5.1 Web API控制器

    ASP.NET Web API控制器 介绍 AbpApiController基类 本地化 其他 过滤器 审计日志 授权 反伪造过滤器 工作单元 结果包装和异常处理 结果缓存 校验 模型绑定器 介绍 A ...

  6. ABP官方文档翻译 0.0 ABP官方文档翻译目录

    一直想学习ABP,但囿于工作比较忙,没有合适的契机,当然最重要的还是自己懒.不知不觉从毕业到参加工作七年了,没留下点儿什么,总感觉很遗憾,所以今天终于卯足劲鼓起勇气开始写博客.有些事能做的很好,但要跟 ...

  7. ABP官方文档翻译 1.5 多租户

    多租户 什么是多租户? 数据库和部署架构 多部署-多数据库 单部署-多数据库 单部署-单数据库 单部署-混合数据库 多部署-单/多/混合数据库 ABP的多租户 启用多租户 租主和租户 会话 决定当前租 ...

  8. ABP官方文档翻译 9.3 NHibernate集成

    NHibernate集成 Nuget包 配置 实体映射 仓储 默认实现 自定义仓储 应用程序特定基础仓储类 ABP可以使用任何ORM框架,它内置集成NHibernate.此文档将讲解ABP如何使用NH ...

  9. ABP官方文档翻译 9.2 Entity Framework Core

    Entity Framework Core 介绍 DbContext 配置 在Startup类中 在模块PreInitialize方法中 仓储 默认仓储 自定义仓储 应用程序特定基础仓储类 自定义仓储 ...

随机推荐

  1. FWT模板

    代码来自51nod1570 #include<cstdio> #include<cstring> #include<algorithm> #define MN 50 ...

  2. STL中的nth_element()方法的使用

    STL中的nth_element()方法的使用 通过调用nth_element(start, start+n, end) 方法可以使第n大元素处于第n位置(从0开始,其位置是下标为 n的元素),并且比 ...

  3. dp水一天

    水一些dp的联系题 标签: dp ###hdu_2045 题意 一穿珠子,用三种颜色染色,要求相邻的珠子和两端的珠子不能是同一种颜色,求当有n个珠子的时候有几种染色方案 题解 表示dp[i][j][k ...

  4. 哈密顿绕行世界问题(dfs+记录路径)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2181 哈密顿绕行世界问题 Time Limit: 3000/1000 MS (Java/Others) ...

  5. 解决无限 This file is indented with tabs instead of 4 spaces

    File -> Settings -> Editor -> Code Style -> Java -> Tabs and Indents -> Use tab ch ...

  6. 怎么使用linux命令重启服务器

    一下的命令都可以重启Linux服务器: 1.shutdown -r now 2.reboot 3.startx

  7. JavaScript之BST

    自己尝试用js实现了数据结构的二叉查找树. // node function Node(data) { this.data = data; this.lc = null; this.rc = null ...

  8. 为什么alertView弹出后button会消失的问题

    按option后会有提示:Do not use the label object to set the text color or the shadow color. Instead, use the ...

  9. Linux文件

    Linux文件类型 对于内核而言,所有打开的文件都是通过文件描述符引用(FD),文件描述符是一个非负整数,当打开现有问价或创建一个新文件时,内核向进程返回一个文件描述符. 按照惯例,shell把文件描 ...

  10. gRPC实战

    gRPC是Google开源的一款非常棒的系统间通信工具,完美的communication抽象,构建在protobuf之上的RPC. 下面我们聊聊它的应用场景,grpc为分布式系统而生,可以是系统间通信 ...