<<ABP框架>> 缓存

简介

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(2);
});

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

这段代码应该写在你模块的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="2"/>

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

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

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

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

时间: 2024-10-08 23:36:58

<<ABP框架>> 缓存的相关文章

ABP开发框架前后端开发系列---(15)ABP框架的服务端和客户端缓存的使用

缓存在一个大型一点的系统里面是必然会涉及到的,合理的使用缓存能够给我们的系统带来更高的响应速度.由于数据提供服务涉及到数据库的相关操作,如果客户端的并发数量超过一定的数量,那么数据库的请求处理则以爆发式增长,如果数据库服务器无法快速处理这些并发请求,那么将会增加客户端的请求时间,严重者可能导致数据库服务或者应用服务直接瘫痪.缓存方案就是为这个而诞生,随着缓存的引入,可以把数据库的IO耗时操作,转换为内存数据的快速响应操作,或者把整个页面缓存到缓存系统里面.本篇随笔主要介绍利用ABP框架的支持实现

ABP框架详解(五)Navigation

ABP框架中的Navigation功能用于管理业务系统中所有可用的菜单导航控件,通常在业务系统的首页会有一个全局性的导航菜单,JD商城,天猫,猪八戒网莫不如是.所以为方便起见,Navigation功能默认定义了一个"MainMenu"菜单添加到缓存字典中.该Navigation功能与普通ERP项目中可定制动态生成的导航菜单最大的区别应该是每一个菜单定义(MenuItemDefinition)可以设置一个权限只有用户拥有权限才会显示给该用户,控制更加的细更加的松耦合不是直接绑定到某个用户

【ABP框架系列学习】介绍篇(1)

  0.引言 该系列博文主要在[官方文档]及[tkbSimplest]ABP框架理论研究系列博文的基础上进行总结的,或许大家会质问,别人都已经翻译过了,这不是多此一举吗?原因如下: 1.[tkbSimplest]的相关博文由于撰写得比较早的,在参照官方文档学习的过程中,发现部分知识未能及时同步(当前V4.0.2版本),如[EntityHistory].[Multi-Lingual Engities]章节未涉及.[Caching]章节没有Entity Caching等内容. 2.进一步深入学习AB

【ABP框架系列学习】N层架构(3)

原文:[ABP框架系列学习]N层架构(3) 目录 0.引言 1.DDD分层 2.ABP应用构架模型 客户端应用程序(Client Applications) 表现层(Presentation Layer) 分布式服务层(Distributed Service Layer) 应用层(Application Layer) 领域层 基础设施层 3.使用ABP项目模版快速生成应用程序 0.引言 应用程序的分层是一种广泛接受的技术, 可以降低复杂度和提高代码的可重用性.为了实现分层架构,ABP遵循领域驱动

&lt;&lt;ABP框架&gt;&gt; 功能管理

文档目录 本节内容: 简介 关于 IFeatureValueStore 功能类型 Boolean 功能 Value 功能 定义功能 基本功能属性 其它功能属性 功能层次 检查功能 使用RequiresFeature特性 RequiresFeature特性注意事项 使用 IFeatureChecker IsEnabled GetValue 客户端 isEnabled getValue 功能管理器 对版本的一个提示 简介 大部分SaaS(多租户)应用有不同功能的版本(包),因此你可以提供不同价格和功

详解ABP框架的多租户

(此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 题记:ABP框架对多租户场景提供了很好的支持,内建了多租户的处理机制,今天我们来深入解析一下这一特性. 最近在基于ABP框架(ASP.NET Boilerplate)开发了一个SaaS.所以接下来可能会时不时分享一下ABP方面的文章.今天来介绍一下ABP对多租户提供的支持特性. ABP简介 ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应用程序的新起点,它旨在成为一个

ABP框架详解(四)Feature

ABP框架中存在一个Feature的特性,功能和设计思路非常类似于框架中的Authorization功能,都是来控制用户是否能够继续操作某项功能,不同点在于Authorization默认是应用在IApplicationService上控制用户或者其所属租户是否具有权限访问服务,而Feature应用更为广泛可以控制访问任意类型,但是控制方式更为单纯只有开关(Enable或者Disable),而且是无法控制具体用户的,只能是某些指定的全局范围内.注意Feature也是有父子关系的,只有父Featur

abp框架中使用angularjs访问后台方法

这段时间接触abp框架,使用angularjs方式访问,总结一点 1.访问方式 js模块 对应以下类 注意首字母小写,后续首字母大写 说明: abp 的 Application Service 动态 web api 用的是驼峰命名法,在生成js 的时候,会扫描 实现IApplicationService 接口的实现类,并且 替换掉 AppService 和 ApplicationService 后缀 2.js命名规则遵循大小驼峰方法

查看abp框架异常信息

abp框架中经常出现{"message":"An error has occurred."}的异常,并且也进入不到方法中,如果想查看详细信息,可以采用下面方法 1.修改项目Web.config文件,将<customErrors mode="On" /> 改为<customErrors mode="RemoteOnly" />,我们再次运行程序就可以看见详细信息了.