abp
前言:什么是缓存
缓存就是数据交换的缓冲区(称作cache),当某一方法要读取数据时,会首先从缓存中查找需要的数据,如果找到了则直接执行,找不到的话则从数据库中找。由于缓存的运行速度比数据库查找速度快得多,故缓存的作用就是帮助系统更快地运行。
图解原理
下面就让我们看看ABP是怎么实现缓存机制的吧
我们实现缓存主要包括4个部分:
- ICache->CacheBase->AbpMemoryCache:对缓存的抽象以及实现;
- ITypedCache:缓存的泛型实现;
- ICacheManager->CacheManagerBase->AbpMemoryCacheManager:缓存管理类的抽象和实现,代码中可以通过注入ICacheManager来获取缓存;
- ICachingconfiguration->CachingConfiguration:用来配置使用哪种缓存。
一. 使用ICacheMananger实现缓存
1.1:使用
如果使用ICacheMananger缓存,我们只需要通过依赖注入把缓存声明就可以了
private readonly IRepository<Person, int> _entityRepository; //声明Person存储仓
private readonly ICacheManager _cacheManager;//依赖注入缓存
public PersonCacheAPPlicationService(IRepository<Person, int> entityRopository
, ICacheManager cacheManager)
{
_cacheManager = cacheManager;//依赖注入缓存
_entityRepository = entityRopository;
}
//在接口中使用
public async Task<List<Person>> GetAll()
{
// var entity = await _entityRepository.GetAllListAsync();
var entityCache = await _cacheManager.GetCache("PeopelCache") //缓存的唯一表示名
.Get("Peopel", () => _entityRepository.GetAllListAsync());
return entityCache;
}
然后我们怎么监控缓存的使用情况呢?
我们在缓存点加个小断点,监视窗口输入 _cacheManager.GetCache("PeopelCache"),就可以查看到它的缓存信息了
我们可以看到缓存的时间是1个小时(默认的),变化时间是空,名字是PeopelCache
1.2我们了解到,它还有个ITypedCache泛型版本
把代码改为这样便可
var entityCache = _cacheManager.GetCache("controllerCache")
.AsTyped<string,List<Person>>()
.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接口中的属性获取方法来自由的配置并且初始化它们。
二.使用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<PersonCacheItem>
{
}
最后,我们就可以创建缓存类来缓存Person实体:
ItransientDependency:所有实现此接口的类都自动注册到依赖项
IPersonCache:缓存类接口
EntityCache<A,B>:把A的数据缓存到B中
public class PersonCache : EntityCache<Person, PersonCacheItem>, IPersonCache, ITransientDependency
{
public PersonCache(ICacheManager cacheManager, IRepository<Person> repository)
: base(cacheManager, repository)
{
}
}
在接口处使用了
public class PersonCacheApplicationService : AbpDemoAppServiceBase
{
private readonly IPersonCache _personCache;
public PersonCacheApplicationService(IRepository<Person, int> 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
的依赖,
一段代码:同样在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"));
});
如果出现以下错误,那就是,Redis服务还没开启 ,或没按照
题外话:
翻了下ABP框架的源码,发现
模板自带的Role、User 等自带了一个 RoleManager的实体缓存接口。实现方式与IEntityCache缓存一样
我们来感受一下他的代码
参考文章:http://www.cnblogs.com/sheng-jie/p/6508241.html
https://blog.csdn.net/WuLex/article/details/78409051
相关阅读
一级缓存: 1,在session上面有一个一级缓存;一级缓存的生命周期和session相同,一级缓存最大生命周期就是一个线程;在web环境下
缓存指的是将需要频繁访问的网络内容存放在离用户较近、访问速度更快的系统中,以提高内容访问速度的一种技术。服务器缓存工作原理
ThinkPHP缓存文件写入失败!:./Runtime/Cache/..
最近在学习ThinkPHP框架,从网上down了一个项目,在本地配置这个项目时,出现了一个问题,无法写入/Runtime/Cache缓存,这个问题是权限问题
Chrome浏览器清除页面js文件缓存 Chrome浏览器清除js缓存方法虽然简单,但有些人还是不太会,有些人会去设置里面清除有时候没有用,
缓存中无值(未宕机) 互斥锁 缓存永不过期 缓存宕机 白名单 布隆过滤器 代码实现 前面的文章介绍了缓存的分类和使用的场景