/// <summary> /// QueryCache级别存储 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="cacheValue"></param> internal void CacheData <T>(T cacheValue) { if (DbContext.OpenQueryCache) { if (cacheValue != null) { string sqlQueryCacheKey = GetSqlQueryCacheKey(); string queryCacheKey = GetQueryCacheKey(); //如果缓存中存在,则拿到表单位的缓存并更新 //这里用object类型进行存储,因为字典的value可能有list集合,int,object等多种类型,泛型使用会出现识别异常 if (CacheStorageManager.IsExist(queryCacheKey, out Dictionary <string, object> t)) { //如果超出单表的query缓存键阈值,则按先后顺序进行移除 if (t.Count >= DbContext.QueryCacheMaxCountPerTable) { t.Remove(t.First().Key); } t.AddOrUpdate(sqlQueryCacheKey, cacheValue); CacheStorageManager.Put(queryCacheKey, t, DbContext.QueryCacheExpiredTimeSpan); } //如果缓存中没有表单位的缓存,则直接新增表单位的sql键缓存 else { var dic = new Dictionary <string, object> { { sqlQueryCacheKey, cacheValue } }; CacheStorageManager.Put(queryCacheKey, dic, DbContext.QueryCacheExpiredTimeSpan); } } } }
/// <summary> /// 清空所有缓存 /// </summary> public void FlushAllCache() { if (CacheStorageManager.IsExist(CoffeeSqlConst.GetQueryCacheKeysCacheKey(DbContext.DataBaseName), out HashSet <string> keys)) { foreach (var item in keys) { CacheStorageManager.Delete(item); } } }
/// <summary> /// 构建sql查询缓存的总key /// </summary> /// <returns></returns> private string GetQueryCacheKey(string collectionName = null) { string key = $"{CoffeeSqlConst.CacheKey_QueryCache}{collectionName ?? DbContext.CollectionName}"; //缓存键更新 if (!CacheStorageManager.IsExist(CoffeeSqlConst.GetQueryCacheKeysCacheKey(DbContext.DataBaseName), out HashSet <string> keys)) { keys = new HashSet <string>(); } keys.Add(key); CacheStorageManager.Put(CoffeeSqlConst.GetQueryCacheKeysCacheKey(DbContext.DataBaseName), keys, DbContext.MaxExpiredTimeSpan); return(key); }
/// <summary> /// 更新数据到缓存(Add) /// </summary> /// <typeparam name="TEntity"></typeparam> /// <param name="dbContext"></param> /// <param name="entity"></param> internal void AddCache <TEntity>(TEntity entity) { if (DbContext.OpenTableCache) { var tableName = TableAttribute.GetName(typeof(TEntity)); //如果存在表级别缓存,则更新数据到缓存 if (CacheStorageManager.IsExist(GetTableCacheKey(tableName), out List <TEntity> entities)) { if (TableCachingAttribute.IsExistTaleCaching(typeof(TEntity), out TimeSpan tableCacheTimeSpan)) { entities.Add(entity); //如果过期时间为0,则取上下文的过期时间 CacheStorageManager.Put(GetTableCacheKey(tableName), entities, tableCacheTimeSpan == TimeSpan.Zero ? DbContext.TableCacheExpiredTimeSpan : tableCacheTimeSpan); } } } }
/// <summary> /// 从缓存中获取数据 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="DbContext"></param> /// <returns></returns> internal T GetEntitiesFromCache <T>() { //1.检查是否开启了Query缓存 if (DbContext.OpenQueryCache) { //2.如果QueryCache里面有该缓存键,则直接获取,并从单个表单位中获取到对应sql的值 if (CacheStorageManager.IsExist(GetQueryCacheKey(), out Dictionary <string, object> t)) { string sqlQueryCacheKey = GetSqlQueryCacheKey(); if (t.ContainsKey(sqlQueryCacheKey)) { DbContext.IsFromCache = true; return(TypeConvertHelper.ToGenericType <T>(t[sqlQueryCacheKey])); } } } return(default(T)); }
/// <summary> /// 更新数据到缓存(Delete) /// </summary> /// <typeparam name="TEntity"></typeparam> /// <param name="dbContext"></param> /// <param name="filter"></param> internal void DeleteCache <TEntity>(Expression <Func <TEntity, bool> > filter) { if (DbContext.OpenTableCache) { var tableName = TableAttribute.GetName(typeof(TEntity)); //如果存在表级别缓存,则更新数据到缓存 if (CacheStorageManager.IsExist(GetTableCacheKey(tableName), out List <TEntity> entities)) { if (TableCachingAttribute.IsExistTaleCaching(typeof(TEntity), out TimeSpan tableCacheTimeSpan)) { //从缓存集合中寻找该记录,如果找到,则更新该记录 var list = entities.Where(filter.Compile()).ToList(); if (list != null && list.Any()) { entities.RemoveAll(t => list.Contains(t)); //如果过期时间为0,则取上下文的过期时间 CacheStorageManager.Put(GetTableCacheKey(tableName), entities, tableCacheTimeSpan == TimeSpan.Zero ? DbContext.TableCacheExpiredTimeSpan : tableCacheTimeSpan); } } } } }
/// <summary> /// 更新数据到缓存(Update) /// </summary> /// <typeparam name="TEntity"></typeparam> /// <param name="dbContext"></param> /// <param name="entity"></param> /// <param name="filter"></param> internal void UpdateCache <TEntity>(TEntity entity, Expression <Func <TEntity, bool> > filter, IEnumerable <string> updateCloumns = null) { if (DbContext.OpenTableCache) { var tableName = TableAttribute.GetName(typeof(TEntity)); //如果存在表级别缓存,则更新数据到缓存 if (CacheStorageManager.IsExist(GetTableCacheKey(tableName), out List <TEntity> oldEntities)) { if (TableCachingAttribute.IsExistTaleCaching(typeof(TEntity), out TimeSpan tableCacheTimeSpan)) { //如果过期时间为0,则取上下文的过期时间 TimeSpan timeSpan = tableCacheTimeSpan == TimeSpan.Zero ? DbContext.TableCacheExpiredTimeSpan : tableCacheTimeSpan; //从缓存集合中寻找该记录,如果找到,则更新该记录 var list = oldEntities.Where(filter.Compile()).ToList(); if (list != null && list.Any()) { List <TEntity> newEntities; oldEntities.RemoveAll(t => list.Contains(t)); if (null == updateCloumns) { //改变了多条,更新对应字段 newEntities = UpdateEntitiesField(oldEntities, entity, updateCloumns); } else { //只改变了传入的唯一一条 newEntities = oldEntities; newEntities.Add(entity); } CacheStorageManager.Put(GetTableCacheKey(tableName), newEntities, timeSpan); } } } } }
/// <summary> /// 更新数据到缓存(Delete) /// </summary> /// <typeparam name="TEntity"></typeparam> /// <param name="dbContext"></param> /// <param name="entity"></param> internal void DeleteCache <TEntity>(TEntity entity) { if (DbContext.OpenTableCache) { var tableName = TableAttribute.GetName(typeof(TEntity)); //如果存在表级别缓存,则更新数据到缓存 if (CacheStorageManager.IsExist(GetTableCacheKey(tableName), out List <TEntity> entities)) { if (TableCachingAttribute.IsExistTaleCaching(typeof(TEntity), out TimeSpan tableCacheTimeSpan)) { //如果过期时间为0,则取上下文的过期时间 TimeSpan timeSpan = tableCacheTimeSpan == TimeSpan.Zero ? DbContext.TableCacheExpiredTimeSpan : tableCacheTimeSpan; //从缓存集合中寻找该记录,如果找到,则更新该记录 var val = entities.Find(t => t.Equals(entity)); if (val != null) { entities.Remove(val); CacheStorageManager.Put(GetTableCacheKey(tableName), entities, tableCacheTimeSpan); } } } } }
/// <summary> /// 后台扫描全表数据 /// </summary> /// <typeparam name="TEntity"></typeparam> /// <param name="dbContext">上下文</param> /// <param name="tableCacheTimeSpan">tableCache过期时间</param> private void ScanTableBackground <TEntity>(TimeSpan tableCacheTimeSpan) where TEntity : class { string scanKey = $"{CoffeeSqlConst.CacheKey_TableScanning}{DbContext.CollectionName}"; //1.判断正在扫描键是否存在,如果存在,则返回null,继续等待扫描任务完成 if (CacheStorageManager.IsExist(scanKey)) { return; } //2.如果没有扫描键,则执行后台扫描任务 Task.Run(() => { //设置扫描键,标识当前正在进行扫描 CacheStorageManager.Put(scanKey, 1, CoffeeSqlConst.SpanScaningKeyExpiredTime); //对扫描任务加锁,防止多线程环境多次执行任务 lock (tableScaningLocker) { var tableName = TableAttribute.GetName(typeof(TEntity)); //双重校验当前缓存是否存在TableCache,防止多个进程在锁外等待,所释放后再次执行 if (CacheStorageManager.IsExist(GetTableCacheKey(tableName))) { return; } //如果过期时间为0,则取上下文的过期时间 TimeSpan timeSpan = tableCacheTimeSpan == TimeSpan.Zero ? DbContext.TableCacheExpiredTimeSpan : tableCacheTimeSpan; //执行扫描全表任务,并将结果存入缓存中 var data = DbContext.GetFullCollectionData <TEntity>(); if (data != null) { CacheStorageManager.Put(GetTableCacheKey(tableName), data, DbContext.TableCacheExpiredTimeSpan); } } //将扫描键移除,表示已经扫描完成 CacheStorageManager.Delete(scanKey); }); }
/// <summary> /// 从缓存中获取数据,如果没有,则后台执行扫描表任务 /// </summary> /// <typeparam name="TEntity"></typeparam> /// <param name="dbContext"></param> /// <param name="filter"></param> /// <returns></returns> internal List <TEntity> GetEntitiesFromCache <TEntity>(Expression <Func <TEntity, bool> > filter) where TEntity : class { //1.检查是否开启了Table缓存 if (!DbContext.OpenTableCache) { return(null); } //2.如果TableCache里面有该缓存键,则直接获取 if (CacheStorageManager.IsExist(GetTableCacheKey(TableAttribute.GetName(typeof(TEntity))), out List <TEntity> entities)) { DbContext.IsFromCache = true; return(entities.Where(filter.Compile()).ToList()); } //3.则判断是否需要对该表进行扫描(含有TableCachingAttribute的标记的类才可以有扫描全表的权限) if (TableCachingAttribute.IsExistTaleCaching(typeof(TEntity), out TimeSpan tableCacheTimeSpan)) { //执行扫描全表数据任务 ScanTableBackground <TEntity>(tableCacheTimeSpan); } return(null); }