zoukankan      html  css  js  c++  java
  • ABP之Caching

    简介

    ABP提供缓存抽象,默认使用MemoryCache。但是可以替换成其他缓存程序,比如 Abp.RedisCache 是使用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”是两个不同的缓存。

    ICache

     ICacheManager.GetCache返回一个ICache,缓存是单例的,是在第一次请求被创建,然后总是返回相同的对象。通过这种方式,我们可以在不同的类(客户端)中使用相同的名称共享相同的缓存。

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

    • key:缓存中项的唯一键(字符串)。
    • factory:如果没有具有给定键的Item,则调用该Action。工厂方法应该创建并返回实际的Item。如果给定键存在于缓存中,则不调用该Action。

    ICache接口还具有GetOrDefault、Set、Remove和Clear等方法,所有方法都有异步版本。

    ITypedCache

     ICache 接口使用字符串作为key,object对象作为value,ITypedCache是ICache的一个包装器,用于提供类型安全的通用缓存。我们可以使用通用的GetCache扩展方法来获得一个ITypedCache:

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

    我们还可以使用AsTyped扩展方法将现有的ICache实例转换为ITypedCache。

    配置

    默认的缓存过期时间是60分钟,如果在60分钟之内不使用缓存中的Item,它就会被自动从缓存中删除。我们可以为所有的缓存配置过期时间,也可以为特定的缓存配置特定时间。

    //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获取实体并希望通过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属性,因为我们希望使用AutoMapper将Person实体自动转换为PersonCacheItem对象。如果我们不使用AutoMapper,我们应该覆盖EntityCache类的MapToCacheItem方法来手动转换/映射它。

    虽然这不是必需的,但我们最好给缓存类定义一个接口:

    public interface IPersonCache : IEntityCache<PersonCacheItem>
    {
    
    }

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

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

    如上所示,我们的Person缓存已准备好使用! 缓存类可以是瞬态的(如本例所示),也可以是单例的。这并不意味着缓存的数据是瞬时的。它总是全局缓存,并在应用程序中以线程安全的方式访问。

    当我们想获取一个人的名字时,我们可以使用这个人的Id从缓存中获取,比如:

    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将实体映射到缓存项,IObjectMapper由AutoMapper模块实现,可以覆盖MapToCacheItem方法来手动将实体映射到缓存项。
    • 它使用cache类的FullName作为缓存名,可以通过将缓存名传递给基本构造函数来更改它。
    • 它是线程安全的。

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

    Redis缓存集成

    默认的缓存管理器使用内存缓存。如果有多个并发web服务器运行相同的应用程序,则可能会出现问题。在这种情况下,可能需要一个分布式/中央缓存服务器,可以使用Redis作为缓存服务器。

    首先需要将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="2"/>

    不同的数据库id对于在同一服务器中创建不同的键空间(隔离缓存)非常有用。

    UseRedis方法还有一个重载,它采取一个操作来直接设置选项值(这将覆盖配置文件中的值)。

    有关Redis及其配置的更多信息,请参阅Redis文档: Redis documentation

     注意:应该安装并运行Redis服务器来使用ABP中的Redis缓存。

  • 相关阅读:
    升级 asp.net core 1.1 到 2.0 preview
    【asp.net core】Publish to a Linux-Ubuntu 14.04 Server Production Environment
    CEF 各个版本适应的平台参考表
    VC2012编译CEF3-转
    【WebKit内核 CEF3 】 第一篇:下载分支代码并本地编译
    INNODB自增主键的一些问题 vs mysql获得自增字段下一个值
    Mysql的批量导入类 MySqlBulkLoader
    一个产生随机数字 字符串验证码 日期的类扩展实现
    asp web api json 序列化后 把私有字段信息也返回了解决办法
    使用Elasticsearch 与 NEST 库 构建 .NET 企业级搜索
  • 原文地址:https://www.cnblogs.com/yixuanhan/p/10790390.html
Copyright © 2011-2022 走看看