缓存就是数据交换的缓冲区(称作Cache),当某一方法要读取数据时,会首先从缓存中查找需要的数据,如果找到了则直接执行,找不到的话则从数据库中找。由于缓存的运行速度比数据库查找速度快得多,故缓存的作用就是帮助系统更快地运行。
图解原理
我们实现缓存主要包括4个部分:
如果使用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"),就可以查看到它的缓存信息了
我们可以看到缓存的时间是1个小时(默认的),变化时间是空,名字是PeopelCache
把代码改为这样便可
var entityCache = _cacheManager.GetCache("ControllerCache")
.AsTyped>()
.Get("AllUsers", () => _entityRepository.GetAllList());
ICacheManager.GetCache方法返回了一个ICache对象的。
而我们上面用到的是ICache对象的Get方法。ICache接口还有其它方法,例如:GetOrDefault,Set(设置缓存),Remove(移除缓存)和Clear(清除缓存)。当然也有这些方法的异步(async)版本。
缓存的过期时间默认是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(); //清除缓存
还有很多缓存操作可以了借鉴。自行尝试
为什么又要学使用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,上面的缓存操作是缓存在系统内存的。
然而我们想要集成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的连接错误我还没很好的办法铺抓
那只能用别的方法测试下,连接是否正常
安装ServiceStack.Redis;包 用 ServiceStack.Redis;连接下看缓存服务器是否可用
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缓存一样
我们来感受一下他的代码
参考文章:http://www.cnblogs.com/sheng-jie/p/6508241.html
https://blog.csdn.net/WuLex/article/details/78409051