ABP-缓存

前言:什么是缓存

缓存就是数据交换的缓冲区(称作Cache),当某一方法要读取数据时,会首先从缓存中查找需要的数据,如果找到了则直接执行,找不到的话则从数据库中找。由于缓存的运行速度比数据库查找速度快得多,故缓存的作用就是帮助系统更快地运行。

图解原理

ABP-缓存_第1张图片

下面就让我们看看ABP是怎么实现缓存机制的吧

我们实现缓存主要包括4个部分:

  • ICache->CacheBase->AbpMemoryCache:对缓存的抽象以及实现;
  • ITypedCache:缓存的泛型实现;
  • ICacheManager->CacheManagerBase->AbpMemoryCacheManager:缓存管理类的抽象和实现,代码中可以通过注入ICacheManager来获取缓存;
  • ICachingConfiguration->CachingConfiguration:用来配置使用哪种缓存。

一. 使用ICacheMananger实现缓存

1.1:使用

如果使用ICacheMananger缓存,我们只需要通过依赖注入把缓存声明就可以了

 private readonly IRepository _entityRepository; //声明Person存储仓
        private readonly ICacheManager _cacheManager;//依赖注入缓存
        public PersonCacheApplicationService(IRepository entityRopository
            , ICacheManager cacheManager)
        {

            _cacheManager = cacheManager;//依赖注入缓存
            _entityRepository = entityRopository;

        }

//在接口中使用

    public async Task> GetAll()
        {

           // var entity = await _entityRepository.GetAllListAsync();
            var entityCache = await _cacheManager.GetCache("PeopelCache") //缓存的唯一表示名
                .Get("Peopel", () => _entityRepository.GetAllListAsync());
            return entityCache;
        }

然后我们怎么监控缓存的使用情况呢?

我们在缓存点加个小断点,监视窗口输入 _cacheManager.GetCache("PeopelCache"),就可以查看到它的缓存信息了

ABP-缓存_第2张图片

ABP-缓存_第3张图片

我们可以看到缓存的时间是1个小时(默认的),变化时间是空,名字是PeopelCache

1.2我们了解到,它还有个ITypedCache泛型版本

把代码改为这样便可

  var entityCache =  _cacheManager.GetCache("ControllerCache")
                                    .AsTyped>()
                                   .Get("AllUsers", () =>  _entityRepository.GetAllList());

1.3了解一下ICache对象。

ICacheManager.GetCache方法返回了一个ICache对象的。

而我们上面用到的是ICache对象的Get方法。ICache接口还有其它方法,例如:GetOrDefault,Set(设置缓存),Remove(移除缓存)和Clear(清除缓存)。当然也有这些方法的异步(async)版本。

1.4Configuration设置缓存时间

缓存的过期时间默认是60分钟。它是变化的。如果你在60分钟内没有使用该缓存,该缓存会被自动的移除。如果你想改变所有的缓存或者指定的缓存来的默认过期时间,你可以这样做,实现如下:

在web.Core层 找到  项目名WebCoreModule  下的 PreInitialize()方法 加入

   //配置所有Cache的默认过期时间为2小时
            Configuration.Caching.ConfigureAll(
                cache =>
                {
                    cache.DefaultAbsoluteExpireTime = TimeSpan.FromHours(2);
                });
            配置指定的Cache过期时间为1天
            Configuration.Caching.Configure(
                "PeopelCache", cache =>
                {
                    cache.DefaultAbsoluteExpireTime = TimeSpan.FromDays(1);
                });

我们可以看到PeopelCache 这个缓存 过期时间改为了一天,变化时间改为了2个小时了

这些配置将会在首次创建缓存的时候生效。配置不仅仅局限于DefaultSlidingExpireTime,你可以利用ICache接口中的属性获取方法来自由的配置并且初始化它们。

可以手动清除缓存

//清除指点缓存
 _cacheManager.GetCache("BasBloodTransfusionReactionCache").Remove("BasBloodTransfusionReaction");

//清除全部缓存
_cacheManager.Dispose(); //清除缓存

还有很多缓存操作可以了借鉴。自行尝试

ABP-缓存_第4张图片

二.使用IEntityCache对实体进行缓存

 

为什么又要学使用IEntityCache缓存呢?

我们可以看到,使用ICacheMananger缓存是有过期时间的,在网上看到一个很好的例子:受到了一个时间的限制我们缓存的用户列表,它是一个实时会变化的集合,而这个实时是不定时的,可能1mins之内就有新用户注册,也有可能几天没有用户注册,这个时候就不好设置缓存过期(刷新)时间。

 

当我们需要通过ID获取实体数据而又不想经常去数据库查询时,我们就可以使用IEntityCache。

换句话说,IEntityCache支持按实体Id进行动态缓存。

 

IEntityCache缓存是,不需要设置缓存过期时间,当数据变化的时候就能自动重新缓存。

可以看到这是我们的实体

  [Table("Person")]
    public class Person : FullAuditedEntity
    {
        public string Name { get; set; }
        public int Sex { get; set; }
    }

并且,假设我们通过该实体的Id,需要频繁调用取得Person实体的Name。首先,我们应该创建一个类来存储 cache items

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

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

 

定义一个接口为缓存类的接口:

public interface IPersonCache : IEntityCache
{

}

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

ITransientDependency:所有实现此接口的类都自动注册到依赖项

IPersonCache:缓存类接口

EntityCache:把A的数据缓存到B中

public class PersonCache : EntityCache, IPersonCache, ITransientDependency
{
    public PersonCache(ICacheManager cacheManager, IRepository repository)
        : base(cacheManager, repository)
    {

    }
}

在接口处使用了

  public class PersonCacheApplicationService : AbpDemoAppServiceBase
    {
        private readonly IPersonCache _personCache;
        public PersonCacheApplicationService(IRepository entityRopository
           )
        {   _personCache = personCache;  }
//如果查询为空,会报错,最好加个错误判断
   public string GetPersonNameById(int id)
    {
            try
            {
                return _personCache[id].Name; //alternative: _personCache.Get(id).Name;
            }
            catch {
                return "值为空";  }
   }}

我们整个的思路是

  • 在首次调用的时候我们通过仓储从数据库中取得实体。那么随后的调用都是从缓存中取得。

  • 如果实体被更新或者删除,它会自动的无效实体。因此,它会在下次调用的时候重新从数据库中检索数据。

  • 使用 IObjectMapper 接口来映射实体到缓存项。IObjectMapper 接口在 AutoMapper 中被实现。

  • 使用缓存类缓存Name

三.Redis Cache 集成

如果们不集成Redis Cache,上面的缓存操作是缓存在系统内存的。

然而我们想要集成RedisCahe 只需要在添加一个安装包,一个依赖,一段代码和就完成了

当然了,首先我们得装一个Redis(我就不展开了):https://blog.csdn.net/wangwengrui40/article/details/86599702

一个安装包:下载Abp.RedisCache Nuget包安装。

一个依赖:在:web.Core层 找到  项目名WebCoreModule 的 DependsOn特性上添加对AbpRedisCacheModule的依赖,

ABP-缓存_第5张图片

 

一段代码:同样在web.Core层 找到  项目名WebCoreModule  下的 PreInitialize()方法 加入,就可以使用本地的Redis了。

 

 //配置使用Redis缓存
            Configuration.Caching.UseRedis();

如果我们想陪着外网的Redis,那么只需要改下链接字符串 

password:Redis密码

connectTimeout:连接超时时间,这里设置的是1000毫秒

connectRetry:重试连接次数

syncTimeout:同步操作默认超时时间

DatabaseId:选中的数据库

            Configuration.Caching.UseRedis(
                options =>
                       {//服务器地址
options.ConnectionString = "192.168.1.181:6379,Password = 123456,connectTimeout=1000,connectRetry=1,syncTimeout=1000";
                           options.DatabaseId = Convert.ToInt32(_appConfiguration.GetConnectionString("RedisCacheDatabaseId"));
                       });

 

ABP-缓存_第6张图片

 

如果出现以下错误,那就是,Redis服务还没开启 ,或没按照

ABP-缓存_第7张图片

如果想启动的时候,不受连接错误的影响怎么办

ABP的连接错误我还没很好的办法铺抓

那只能用别的方法测试下,连接是否正常

安装ServiceStack.Redis;包 用 ServiceStack.Redis;连接下看缓存服务器是否可用

ABP-缓存_第8张图片

        public static PooledRedisClientManager CreateManager(string Connection)
             {
            //ConfigurationManager.ConnectionStrings["RedisSlaveServerIP"]
            var ConnectionString = Connection;
            // 读取 Redis 主机 IP 配置信息
            string[] redisMasterHosts = ConnectionString.Split(',');

            // 如果 Redis 服务器是主从配置,那么还需要读取 Redis Slave 机的 IP 配置信息
            string[] redisSlaveHosts = ConnectionString.Split(',');

            PooledRedisClientManager Manager = null;
                 if (Manager == null)
                 {
                     Manager = new PooledRedisClientManager(redisMasterHosts, redisSlaveHosts, new RedisClientManagerConfig()
                     {
                         MaxWritePoolSize = 5,
                         MaxReadPoolSize = 5,
                         AutoStart = true
                     }, 0, 50, 5);
                 }
            Manager.GetClient();
            Manager.Dispose();
                 return Manager;
             }

 

题外话:

翻了下ABP框架的源码,发现

模板自带的Role、User 等自带了一个 RoleManager的实体缓存接口。实现方式与IEntityCache缓存一样

我们来感受一下他的代码

ABP-缓存_第9张图片

ABP-缓存_第10张图片

参考文章:http://www.cnblogs.com/sheng-jie/p/6508241.html

https://blog.csdn.net/WuLex/article/details/78409051

 

你可能感兴趣的:(ABP学习,ASP.net,Core)