ABP module-zero +AdminLTE+Bootstrap Table+jQuery权限管理系统第十五节--缓存小结与ABP框架项目中 Redis Cache的实现...

返回总目录:ABP+AdminLTE+Bootstrap Table权限管理系统一期

缓存

为什么要用缓存

为什么要用缓存呢,说缓存之前先说使用缓存的优点。

  • 减少寄宿服务器的往返调用(round-trips)。
  • 如果缓存在客户端或是代理,将减少对服务器的请求,减少带宽。
  • 减少对数据库服务器的往返调用(round-trips)。
  • 当内容缓存在web服务器,能够减轻对数据库的请求。
  • 减少网络带宽。
  • 避免了重新生成可重用内容的时耗。
  • 提高性能
  • 因为缓存减少了round-trips, network traffic(网络带宽),并避免- 了生成可重用内容的时耗,所以对性能有巨大的提高。

传统的缓存方式

传统的缓存方式如下面这张图
image.png
之前我们处理方式处理起来也很简单

  1. 页面输出缓存,直接在 ASP.NET中页面缓存的使用OutputCache 在aspx页的顶部加这样一句即可:
    <%@ OutputCache Duration="60" VaryByParam="none" %>
    Duration 表示缓存的时间秒,必选,否则报错。
  2. 第二种方式
    if (this.Cache["Keys"] == null) { this.Cache.Insert("Keys", List, null, DateTime.Now.AddHours(2), TimeSpan.Zero); }

这里是检查缓存中Keys是否存在,如果不存在,则写入一个新的值List.还有其他的一些使用方法。
image.png

上面两种方式显然不在现在使用范畴,也不在我想说的范畴之内。,年代貌似有点久远,不用webform基本用不到。现在我们更多是的使用MVC。
我们想说的是MVC输出缓存。

MVC缓存

输出缓存Outputcache ,分为Action输出缓存和Controller输出缓存。使用的场景包括某个页面的数据更新不是很频繁,不需要每次都从数据库区查询。缓存起来从内存中读取。

数据缓存:是相对于全局的。任何地方需要调用的时候都可以去调用。使用的场景包括权限管理这种模块的。每个角色对于菜单的访问都是固定的,所以有必要将角色,权限,菜单这种数据做一个全局的数据缓存。修改时再做缓存的更新。

输出缓存和数据缓存区别:打个比方输出缓存就像是“局部变量”,数据缓存就像是全局变量(只是个比喻)。

Controller输出缓存和 Action缓存使用方式是一样的,就是Controller 或Action上打[OutPutCache]特性标签。但是他们之间又是有区别的。

一、控制器缓存

Control缓存的作用域是整个控制器,所以在这个控制器下的所有Action都会被缓存起来。Control缓存的粒度比较粗,应用也比较少些。
[OutputCache(Duration = 10)] public class HomeController : Controller { public ActionResult Index() { ViewBag.CurrentTime = DateTime.Now; return View(); } }

二、Action缓存

将[OutPutCache]特性标签打在Action上,这样,只有加缓存的Action才会有缓存,其他的Action是没有的。

Outputcache特性常用的属性参数

名称描述
AllowMultiple获取或设置一个值,该值指示是否可指定筛选器特性的多个实例。
CacheProfile获取或设置缓存配置文件名称。
ChildActionCache获取或设置子操作缓存。
Duration获取或设置缓存持续时间(以秒为单位)。
Location获取或设置位置。
NoStore获取或设置一个值,该值指示是否存储缓存。
Order获取或者设置执行操作筛选器的顺序。
SqlDependency获取或设置 SQL 依赖项。
TypeId(从Attribute继承。)
VaryByContentEncoding获取或设置基于内容变化的编码。
VaryByCustom获取或设置基于自定义项变化的值。
VaryByHeader获取或设置基于标头变化的值。
VaryByParam获取或设置基于参数变化的值。

输出缓存CacheProfile使用配置文件设置缓存

举例其中的CacheProfile,这种方式便于统一配置,当然也可以设置参数duration、location 、varybyparam等。我们需要在system.web 节点下加入这些

<!---CacheProfile配置文件中设置缓存--> <caching> <outputCacheSettings> <outputCacheProfiles> <add name="TestConfigCache" duration="20" location="Any" enabled="true"/> </outputCacheProfiles> </outputCacheSettings> </caching> <!---CacheProfile配置文件中设置缓存end-->
其实作用和效果还是一样,无非就是方便点,统一的配置参数都直接写webconfig文件里面。其实也可以Controller中写。
配置好了之后我们直接在控制器调用相应的名字的OutputCache特性标签即可。
[OutputCache(CacheProfile= "TestConfigCache")] public ActionResult Index() { ViewBag.CurrentTime = DateTime.Now; return View(); }
更多的方式,需要下去再研究下。

ABP Redis Cache

ABP中使用ICacheManager进行缓存管理

ABP中有两种cache的实现方式:MemroyCacheRedisCache,两者都继承至ICache接口(准确说是CacheBase抽象类)。ABP核心模块封装了MemroyCache来实现ABP中的默认缓存功能。 Abp.RedisCache这个模块封装RedisCache来实现缓存(通过StackExchange.Redis这个类库访问redis)。

ABP给出了一个抽象缓存基类。并在内部使用了该抽象基类。使用 MemoryCache 来实现了该抽象基类。它能够被任何其它的缓存类来扩展。Abp.RedisCache 包就扩展了该缓存基类。
ABP对外提供了一个缓存接口ICacheMananger。我们通过构造函数注入这个接口来获取缓存。示例如下:
image.png

在这个示例中,我们注入了 ICacheManager接口,s并且获取了一个名称为ControllerCache的缓存。首先我们先对ControllerCache进行清除,然后存入缓存,缓存的名字是大小写敏感的,那就是"ControllerCache"和"CONTROLLERCACHE"取得的缓存内容是不同的。

注意:GetCache方法 千万不要在你的构造函数中使用GetCache方法。如果类不是一个单例对象那么该缓存可能会被dispose掉。

ICache

ICacheManager.GetCache方法返回了一个ICache对象。每一个缓存都是基于名称单例存在的。只有首次访问时才会被创建,以后你每次用相同的名称去获取的缓存都是相同的。所以我们可以在不同的类中使用相同的名称来共享相同的缓存。

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

  • key : 要获取的缓存项的唯一标识符
  • factory:如果根据给定的key获取到的缓存项为空,那么factory将会创建一个标识符为key的缓存,并且返回该缓存

ICache接口还有其它方法,如前面Clear(),Get(),GetOrDefaultSetRemoveClear。当然也有这些方法的异步(async)版本。如下图,我就懒得写了。
image.png

ITypedCache

ICache 接口用key(字符串类型)来获取缓存value(object类型)。ITypedCacheICahe提供了一个 类型安全 的包装;为了使类型安全转换(ICacheITypedCache),我们可以用扩展方法 AsTyped,而不需要写其它强制类型转换的代码,如下所示:
ITypedCache<int, Item> myCache = _cacheManager.GetCache("MyCache").AsTyped<int, Item>();

Configuration

缓存的过期时间默认是60分钟。它是变化的。如果你在60分钟内没有使用该缓存,该缓存会被自动的移除。如果你想改变所有的缓存或者指定的缓存来的默认过期时间,你可以这样做,实现如下:
//对所有缓存的配置 Configuration.Caching.ConfigureAll(cache => { cache.DefaultSlidingExpireTime = TimeSpan.FromHours(2); });
//对指定缓存的配置 Configuration.Caching.Configure("MyCache", cache => { cache.DefaultSlidingExpireTime = TimeSpan.FromHours(8); });

这段代码你应该放在模块(module)的 PreInitialize 方法中。如上所示:MyCache将会在8小时后过期,而其他的缓存将在2小时后过期。

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

Entity Caching

ABP的缓存系统是以通用为目的,它有一个 EntityCache 基类,如果你需要的话,这个基类可以帮助你缓存实体。使用这个基类,我们可以通过ID取得实体,并且我们通过ID来缓存实体,这样以后就不需要频繁的查询数据库去取得实体。假设我们有个Person实体,像下面一样:
public class Person : Entity { public string Name { get; set; } public int Age { 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<PersonCacheItem> { }
最后,我们可以创建缓存类来缓存Person实体:
public class PersonCache : EntityCache<Person, PersonCacheItem>, IPersonCache, ITransientDependency { public PersonCache(ICacheManager cacheManager, IRepository<Person> repository) : base(cacheManager, repository) { } }

这样就OK了,我们的person缓存已经准备好可以使用了。缓存类可以使瞬时(如同这个例子)或者是单例。这不是说缓存数据是瞬态的。在你的应用程序中它一直是全局缓存并且是线程安全的。

现在,无论在什么地方我们需要取得Person的Name,我们可以通过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 中被实现。所以,如果你使用了自动映射,那么就需要 AutoMapper模块。你可以重写 MapToCacheItem 方法手动映射它到缓存项。
  • 使用缓存类的FullName作为缓存的Name,你可以通过传入的缓存名到基类的构造函数来改变它。
  • 它是线程安全的。
    如果你有更复杂的缓存需求,那么你需要扩展 EntityCache 类或者创建你自己的解决方案。

Redis Cache 集成

Redis是什么,Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。它可以用作数据库、缓存和消息中间件。它支持多种类型的数据结构,如字符串(strings)、散列(hashes)、列表(lists)、集合(sets)、有序集合(sorted sets)与范围查询、bitmaps、hyperloglogs和地理空间(geospatial)索引半径查询。
Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。
Redis 与其他 key - value 缓存产品有以下三个特点

  • Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
  • Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
  • Redis支持数据的备份,即master-slave模式的数据备份。
    Redis 优势
  • 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
  • 丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
  • 原子 – Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。
  • 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。
  • 多实用工具 - Redis是一个多实用工具,可用于多种用例,如:缓存,消息队列(Redis本地支持发布/订阅),应用程序中的任何短期数据,例如,web应用程序中的会话,网页命中计数等。

(1)首先,我们前往https://github.com/dmajkic/redis/downloads下载安装包,直接下一步下一步就可以了。
然后打开安装的地址就可以看到如下的文件:
image.png
(2)然后启动Redis服务,我们cmd到安装目录下,然后输入命令redis-server.exe redis.windows.conf
就会看到下面的画面证明我们启动服务成功。
image.png
abp默认Cache Mananger是使用in-memory来缓存。所以,这可能会成为一个问题,如果有多个并发的Web服务运行在同一个应用中。在这种情况下,你可能想要一个分布式/中央缓存服务器。那么,你可以使用Redis来作为你的缓存服务。
首先,你需要安装
Abp.RedisCachenuget package 到你的项目中(你可以安装它到你的Web项目)。这里我遇到一个错误。
image.png
开始的时候我搞了半天不知道为什么会出现这个莫名其妙的错误,后来才发现,原来我引入Abp.RedisCache版本和abp版本不一致。才导致的这个错误,比如你abp是3.1.1,那么你的Abp.RedisCache最好也是对应的版本,最好的话把abp和Abp.RedisCache都升级到最新版本,就不会有错误了。
然后我们看看Abp.Runtime.Caching.Redis;依赖项以及之间的关系。
image.png
然后在ABPCMSWebModule配置一下。
image.png
ABPCMSApplicationModule中引入。
image.png
Web.config中配置
image.png
你也可以添加配置到appSettings来设置Redis数据库的Id。如:
<add key="Abp.Redis.Cache.DatabaseId" value="2"/>
在同一个服务器上使用不同的数据库Id是非常有用的这可以创建不同的Key Spaces(隔离缓存)。
UseRedis有一个重载方法,你可以通过这个方法来传入配置参数,这可以覆盖掉配置文件中的配置。关于Redis的其他配置可以查看Redis文档

在下面UserList打下断点调试进去。
image.png
看到效果如下图,证明我们AbpRedisCache引入成功。
image.png
当然为了更好的进行可视化操作,我建议使用跨平台开源Redis DB管理工具(Redis Desktop Manager)地址:https://redisdesktop.com/download
下载下来直接下一步下一步安装即可。
image.png
然后运行项目,然后我们在看下Redis Desktop Manager工具,效果如下图:
image.png
使用可视化工具很方便

  1. 新建连接,输入redis主机host,端口号port,再起个生动形象,简明达意的别名。
  2. 该工具支持根据筛选条件查询key,add new key,reload等。
  3. 支持常用redis操作,针对目标key执行rename,delete,addrow,reload value操作。
  4. 命令控制台操作 !大家感兴趣可以自己玩一下。
    另外关于实体修改后自动更新缓存的实现远离可以参考
    http://www.cnblogs.com/loyldg/p/using-redis-in-abp-2.html
    这个文章。

Github项目地址:https://github.com/Jimmey-Jiang/ABP-ASP.NET-Boilerplate-Project-CMS
本文链接:http://www.cnblogs.com/anyushengcms/p/8013201.html

ABP+AdminLTE+Bootstrap Table权限管理系统一期
Github:https://github.com/Jimmey-Jiang/ABP-ASP.NET-Boilerplate-Project-CMS
返回总目录:ABP+AdminLTE+Bootstrap Table权限管理系统一期

转载于:https://www.cnblogs.com/anyushengcms/p/8013201.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值