ZhiYeJianKang_PeiXun/cyqdata-master/Aop/AopCache.cs

1079 lines
40 KiB
C#
Raw Normal View History

2025-02-20 15:41:53 +08:00
using CYQ.Data.Aop;
using CYQ.Data.Cache;
using CYQ.Data.Json;
using CYQ.Data.SQL;
using CYQ.Data.Table;
using CYQ.Data.Tool;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.Common;
using System.Reflection;
using System.Text;
using System.Threading;
namespace CYQ.Data.Aop
{
/// <summary>
/// 内部智能缓存AutoCache
/// </summary>
internal static partial class AopCache
{
private static DistributedCache _AopCache = DistributedCache.Instance;//有可能使用MemCache操作
internal static bool GetCache(AopEnum action, AopInfo aopInfo)//Begin
{
switch (action)
{
case AopEnum.ExeNonQuery:
case AopEnum.Insert:
case AopEnum.Update:
case AopEnum.Delete:
return false;
}
if (!IsCanOperateCache(action, aopInfo))
{
return false;
}
string baseKey = GetBaseKey(aopInfo);
//查看是否通知我移除
string key = GetKey(action, aopInfo, baseKey);
object obj = _AopCache.Get(key);
switch (action)
{
case AopEnum.ExeMDataTableList:
if (obj != null)
{
List<MDataTable> list = new List<MDataTable>();
if (obj is List<MDataTable>)
{
List<MDataTable> listObj = obj as List<MDataTable>;
foreach (MDataTable table in listObj)
{
list.Add(table.Clone());
}
}
else
{
Dictionary<string, string> jd = JsonHelper.Split(obj.ToString());
if (jd != null && jd.Count > 0)
{
foreach (KeyValuePair<string, string> item in jd)
{
list.Add(MDataTable.CreateFrom(item.Value, null, EscapeOp.Encode));
}
}
}
aopInfo.TableList = list;
}
break;
case AopEnum.Select:
case AopEnum.ExeMDataTable:
if (obj != null)
{
if (obj is MDataTable)
{
aopInfo.Table = (obj as MDataTable).Clone();
}
else
{
aopInfo.Table = MDataTable.CreateFrom(obj.ToString(), null, EscapeOp.Encode);
}
}
break;
case AopEnum.ExeList:
case AopEnum.SelectList:
case AopEnum.ExeJson:
case AopEnum.SelectJson:
case AopEnum.ExeScalar:
case AopEnum.Exists:
if (obj != null)
{
aopInfo.ExeResult = obj;
}
break;
case AopEnum.Fill:
if (obj != null)
{
MDataRow row;
if (obj is MDataRow)
{
row = (obj as MDataRow).Clone();
}
else
{
row = MDataRow.CreateFrom(obj);
}
aopInfo.Row = row;
aopInfo.IsSuccess = true;
}
break;
case AopEnum.GetCount:
if (obj != null)
{
aopInfo.ExeResult = obj;
}
break;
}
baseKey = key = null;
return obj != null;
}
internal static void SetCache(AopEnum action, AopInfo aopInfo)//End
{
if (!IsCanOperateCache(action, aopInfo))
{
return;
}
string baseKey = GetBaseKey(aopInfo);
switch (action)
{
case AopEnum.ExeNonQuery:
case AopEnum.Insert:
case AopEnum.Update:
case AopEnum.Delete:
if (aopInfo.IsSuccess || (aopInfo.ExeResult is int) && ((int)aopInfo.ExeResult > 0))
{
if (action == AopEnum.Update || action == AopEnum.ExeNonQuery)
{
//检测是否指定忽略的列名(多数据库的指定?{XXX.XXX}
if (!IsCanRemoveCache(action, aopInfo))
{
return;
}
}
ReadyForRemove(baseKey);
}
return;
}
if (_AopCache.CacheType == CacheType.LocalCache && _AopCache.Count > 5000000)//数量超过500万
{
return;
}
string key = GetKey(action, aopInfo, baseKey);
int flag;//0 正常1未识别2不允许缓存
SetBaseKeys(aopInfo, key, out flag);//存档Key后续缓存失效 批量删除
if (flag == 2)
{
return;//
}
double cacheTime = AppConfig.Cache.DefaultMinutes;// Math.Abs(12 - DateTime.Now.Hour) * 60 + DateTime.Now.Second;//缓存中午或到夜里1点
if (flag == 1 || aopInfo.PageIndex > 2) // 后面的页数,缓存时间可以短一些
{
cacheTime = 1;//未知道操作何表时只缓存1分钟比如存储过程等语句
}
switch (action)
{
case AopEnum.ExeMDataTableList:
if (IsCanSetCache(aopInfo.TableList))
{
if (_AopCache.CacheType == CacheType.LocalCache)
{
List<MDataTable> cloneList = new List<MDataTable>(aopInfo.TableList.Count);
foreach (MDataTable table in aopInfo.TableList)
{
cloneList.Add(table.Clone());
}
_AopCache.Set(key, cloneList, cacheTime);
}
else
{
JsonHelper js = new JsonHelper(false, false);
foreach (MDataTable table in aopInfo.TableList)
{
js.Add(Guid.NewGuid().ToString(), table.ToJson(true, true, RowOp.IgnoreNull, false, EscapeOp.Encode));
}
js.AddBr();
_AopCache.Set(key, js.ToString(), cacheTime);
}
}
break;
case AopEnum.Select:
case AopEnum.ExeMDataTable:
if (IsCanSetCache(aopInfo.Table))
{
if (_AopCache.CacheType == CacheType.LocalCache)
{
_AopCache.Set(key, aopInfo.Table.Clone(), cacheTime);
}
else
{
_AopCache.Set(key, aopInfo.Table.ToJson(true, true, RowOp.IgnoreNull, false, EscapeOp.Encode), cacheTime);
}
}
break;
case AopEnum.ExeJson:
if (IsCanSetCache(aopInfo.ExeResult))
{
_AopCache.Set(key, aopInfo.ExeResult, cacheTime);
}
break;
case AopEnum.ExeList:
if (IsCanSetCache(aopInfo.ExeResult))
{
_AopCache.Set(key, JsonHelper.ToJson(aopInfo.ExeResult, false, RowOp.IgnoreNull, EscapeOp.Encode), cacheTime);
}
break;
case AopEnum.SelectList:
if (IsCanSetCache(aopInfo.ExeResult))
{
JsonHelper js = new JsonHelper(true, true);
js.Escape = EscapeOp.Encode;
if (aopInfo.TotalCount > 0)
{
js.Total = aopInfo.TotalCount;
}
js.LoopCheckList.Add(aopInfo.ExeResult.GetHashCode(), 0);
js.Fill(aopInfo.ExeResult);
string result = js.ToString(true);
_AopCache.Set(key, result, cacheTime);
}
break;
case AopEnum.SelectJson:
if (IsCanSetCache(aopInfo.ExeResult))
{
JsonHelper js = new JsonHelper(false, false);
js.Escape = EscapeOp.Encode;
js.Add("total", aopInfo.TotalCount.ToString(), true);
js.Add("rows", aopInfo.ExeResult.ToString());
_AopCache.Set(key, js.ToString(), cacheTime);
}
break;
case AopEnum.ExeScalar:
_AopCache.Set(key, aopInfo.ExeResult, cacheTime);
break;
case AopEnum.Fill:
if (_AopCache.CacheType == CacheType.LocalCache)
{
_AopCache.Set(key, aopInfo.Row.Clone(), cacheTime);
}
else
{
_AopCache.Set(key, aopInfo.Row.ToJson(RowOp.IgnoreNull, false, EscapeOp.Encode), cacheTime);
}
break;
case AopEnum.GetCount:
_AopCache.Set(key, aopInfo.ExeResult, cacheTime);
break;
case AopEnum.Exists:
_AopCache.Set(key, aopInfo.ExeResult, cacheTime);
break;
}
}
#region
static bool IsCanSetCache(List<MDataTable> dtList)
{
foreach (MDataTable item in dtList)
{
if (!IsCanSetCache(item))
{
return false;
}
}
return true;
}
static bool IsCanSetCache(MDataTable dt)
{
if (dt == null || dt.Rows.Count > 1000)
{
return false;// 大于1000条的不缓存,1000这个数字性能调节上相对合适。
}
if (_AopCache.CacheType != CacheType.LocalCache)
{
foreach (MCellStruct item in dt.Columns)
{
if (DataType.GetGroup(item.SqlType) == DataGroupType.Object)//只存档基础类型
{
return false;
}
}
}
return true;
}
static bool IsCanSetCache(object listResult)
{
//return false;
if (listResult == null)
{
return false;
}
if (!(listResult is String) && listResult is IEnumerable)
{
int i = 0;
foreach (object o in listResult as IEnumerable)
{
if (i == 0)// && _AutoCache.CacheType != CacheType.LocalCache
{
List<PropertyInfo> pis = ReflectTool.GetPropertyList(o.GetType());
foreach (PropertyInfo item in pis)
{
if (DataType.GetGroup(DataType.GetSqlType(item.PropertyType)) == DataGroupType.Object)//只存档基础类型
{
return false;
}
}
}
i++;
if (i > 100)// 大于N条的不缓存。List<T> 的缓存在存和取间都要转2次 JsonString=>MDataTable=>List<T>),所以限制条数少一些,性能调节上相对合适。
{
return false;
}
}
}
return true;
}
#region
private static Dictionary<string, string> _IngoreCacheColumns = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
static readonly object obj = new object();
internal static Dictionary<string, string> IngoreCacheColumns
{
get
{
if (_IngoreCacheColumns.Count == 0)
{
string ignoreColumns = AppConfig.AutoCache.IngoreColumns;
if (!string.IsNullOrEmpty(ignoreColumns))
{
lock (obj)
{
if (_IngoreCacheColumns.Count == 0)
{
_IngoreCacheColumns = JsonHelper.Split(ignoreColumns);
}
}
if (_IngoreCacheColumns == null)
{
Error.Throw("IngoreCacheColumns config must be a json!");
}
}
}
return _IngoreCacheColumns;
}
set
{
if (value == null)
{
_IngoreCacheColumns.Clear();
}
else
{
_IngoreCacheColumns = value;
}
}
}
static bool IsCanRemoveCache(AopEnum action, AopInfo aopInfo)
{
if (IngoreCacheColumns.Count > 0)
{
string databaseName = string.Empty;
if (action == AopEnum.ExeNonQuery)
{
if (aopInfo.IsProc || !aopInfo.ProcName.ToLower().StartsWith("update "))
{
return true;
}
databaseName = aopInfo.MProc.DataBaseName;
}
else
{
databaseName = aopInfo.MAction.DataBaseName;
}
string tableName = aopInfo.TableName;
if (string.IsNullOrEmpty(tableName))
{
List<string> tableNames = SqlFormat.GetTableNamesFromSql(aopInfo.ProcName);
if (tableNames == null || tableNames.Count != 1)//多个表的批量语句也不处理。
{
return true;
}
tableName = tableNames[0];
}
//获取被更新的字段名,
string[] columns = null;
if (IngoreCacheColumns.ContainsKey(tableName))
{
columns = IngoreCacheColumns[tableName].ToLower().Split(',');
}
else if (IngoreCacheColumns.ContainsKey(databaseName + "." + tableName))
{
columns = IngoreCacheColumns[databaseName + "." + tableName].ToLower().Split(',');
}
if (columns != null)//拿到要忽略的列。
{
List<string> updateColumns = GetChangedColumns(action, aopInfo);//拿到已更新的列
if (columns.Length >= updateColumns.Count)
{
List<string> ignoreColumns = new List<string>(columns.Length);
ignoreColumns.AddRange(columns);
foreach (string item in updateColumns)
{
if (!ignoreColumns.Contains(item))
{
return true;//只要有一个不存在。
}
}
return false;//全都不存在
}
}
}
return true;
}
private static List<string> GetChangedColumns(AopEnum action, AopInfo aopInfo)
{
List<string> columns = new List<string>();
string expression = string.Empty;
if (action == AopEnum.Update)
{
foreach (MDataCell item in aopInfo.Row)
{
if (item.State == 2 && !item.Struct.IsPrimaryKey)
{
columns.Add(item.ColumnName.ToLower());
}
}
expression = aopInfo.UpdateExpression;
}
else if (action == AopEnum.ExeNonQuery && !aopInfo.IsProc)
{
string sql = aopInfo.ProcName.ToLower();
int setStart = sql.IndexOf(" set ");
int whereEnd = sql.IndexOf(" where ");
if (whereEnd < setStart)
{
expression = sql.Substring(setStart + 5);
}
else
{
expression = sql.Substring(setStart + 5, whereEnd - setStart + 5);
}
}
if (!string.IsNullOrEmpty(expression))
{
string[] items = expression.ToLower().Split(',');
foreach (string item in items)
{
if (item.IndexOf('=') > -1)
{
string column = item.Split('=')[0];
if (!columns.Contains(column))
{
columns.Add(column);
}
}
}
}
return columns;
}
#endregion
#endregion
#region Key的管理
/// <summary>
/// 单机存档: 表的baseKey:key1,key2,key3...
/// </summary>
private static MDictionary<string, StringBuilder> cacheKeys = new MDictionary<string, StringBuilder>(StringComparer.OrdinalIgnoreCase);
private static void SetBaseKeys(AopInfo para, string key, out int flag)
{
List<string> items = GetBaseKeys(para, out flag);
if (items != null && items.Count > 0)
{
foreach (string item in items)
{
SetBaseKey(item, key);
}
items = null;
}
}
private static void SetBaseKey(string baseKey, string key)
{
//baseKey是表的不包括视图和自定义语句
if (_AopCache.CacheType == CacheType.LocalCache)
{
if (cacheKeys.ContainsKey(baseKey))
{
cacheKeys[baseKey] = cacheKeys[baseKey].Append("," + key);
}
else
{
cacheKeys.Add(baseKey, new StringBuilder(key));
}
}
else
{
StringBuilder sb = _AopCache.Get<StringBuilder>(baseKey);
if (sb == null)
{
_AopCache.Set(baseKey, new StringBuilder(key));
}
else
{
sb.Append("," + key);
_AopCache.Set(baseKey, sb);
}
}
}
//private static List<string> _CacheTables = null;
//internal static List<string> CacheTables
//{
// get
// {
// if (_CacheTables == null)
// {
// _CacheTables = new List<string>();
// string tables = AppConfig.Cache.CacheTables.ToLower();
// if (!string.IsNullOrEmpty(tables))
// {
// _CacheTables.AddRange(tables.Split(','));
// }
// }
// return _CacheTables;
// }
// set
// {
// _CacheTables = value;
// }
//}
//private static List<string> _NoCacheTables = null;
//internal static List<string> NoCacheTables
//{
// get
// {
// if (_NoCacheTables == null)
// {
// _NoCacheTables = new List<string>();
// string tables = AppConfig.Cache.NoCacheTables.ToLower();
// if (!string.IsNullOrEmpty(tables))
// {
// _NoCacheTables.AddRange(tables.Split(','));
// }
// }
// return _NoCacheTables;
// }
// set
// {
// _NoCacheTables = value;
// }
//}
private static bool IsCanOperateCache(AopEnum action, AopInfo para)
{
if (para.IsTransaction) // 事务中,读数据时,处理读缓存是无法放置共享锁的情况
{
//判断事务等级,如果不是最低等级,则事务的查询不处理缓存
switch (action)//处理查询 动作
{
case AopEnum.Exists:
case AopEnum.Fill:
case AopEnum.GetCount:
case AopEnum.Select:
case AopEnum.SelectList:
case AopEnum.SelectJson:
if (para.MAction.dalHelper.TranLevel != System.Data.IsolationLevel.ReadUncommitted)
{
return false;
}
break;
case AopEnum.ExeMDataTable:
case AopEnum.ExeMDataTableList:
case AopEnum.ExeScalar:
case AopEnum.ExeList:
case AopEnum.ExeJson:
if (para.MProc.dalHelper.TranLevel != System.Data.IsolationLevel.ReadUncommitted)
{
return false;
}
break;
}
}
List<string> tables = GetRelationTables(para);
if (tables != null && tables.Count > 0)
{
string cacheTables = "," + AppConfig.AutoCache.Tables + ",";//demo.Aa
string nNoCacheTables = "," + AppConfig.AutoCache.IngoreTables + ",";
foreach (string tableName in tables)
{
if (cacheTables.Length > 2)
{
if (cacheTables.IndexOf("," + tableName + ",", StringComparison.OrdinalIgnoreCase) == -1
&& cacheTables.IndexOf(para.DataBase + "." + tableName + ",", StringComparison.OrdinalIgnoreCase) == -1)
{
return false;
}
}
else if (nNoCacheTables.Length > 2)
{
if (nNoCacheTables.IndexOf("," + tableName + ",", StringComparison.OrdinalIgnoreCase) > -1
|| nNoCacheTables.IndexOf(para.DataBase + "." + tableName + ",", StringComparison.OrdinalIgnoreCase) > -1)
{
return false;
}
}
string baseKey = GetBaseKey(para, tableName);
string delKey = "AutoCache.Delete:" + baseKey;
if (_AopCache.Contains(delKey))
{
return false;
}
}
}
return true;
// string delKey = "DeleteAutoCache:" + baseKey;
// return !_MemCache.Contains(delKey);
//if (baseKey.Contains(".ActionV") || baseKey.Contains(".ProcS"))
//{
// return true;
//}
//TimeSpan ts = DateTime.Now - _MemCache.Get<DateTime>("Del:" + baseKey);
//return ts.TotalSeconds > 6;//5秒内无缓存。
}
private static string GetBaseKey(AopInfo para)
{
return GetBaseKey(para, null);
}
internal static string GetBaseKey(string tableName, string conn)
{
if (string.IsNullOrEmpty(conn))
{
conn = CrossDB.GetConn(tableName, out tableName, conn);
}
return "AutoCache:" + ConnBean.GetHashKey(conn) + "." + tableName;
}
private static string GetBaseKey(AopInfo para, string tableName)
{
if (string.IsNullOrEmpty(tableName))
{
if (para.MAction != null)
{
foreach (MCellStruct ms in para.MAction.Data.Columns)
{
if (!string.IsNullOrEmpty(ms.TableName))
{
tableName = ms.TableName;
break;
}
}
if (string.IsNullOrEmpty(tableName))
{
if (para.TableName.Contains(" "))
{
tableName = "View_" + TableInfo.GetHashKey(para.TableName);
}
else
{
tableName = para.TableName;
}
//if (para.MAction.Data.Columns.isViewOwner)
//{
// tableName = "ActionV" + Math.Abs(para.TableName.GetHashCode());
//}
}
}
else
{
if (!para.IsProc)
{
tableName = SqlSyntax.Analyze(para.ProcName).TableName;
}
else
{
tableName = "Proc_" + para.ProcName;
}
}
}
return GetBaseKey(tableName, para.ConnectionString);
}
private static List<string> GetBaseKeys(AopInfo para, out int flag)
{
flag = 0;//0 正常1未识别2暂不允许缓存
List<string> baseKeys = new List<string>();
List<string> tables = GetRelationTables(para);
if (tables != null && tables.Count > 0)
{
foreach (string tableName in tables)
{
string baseKey = GetBaseKey(para, tableName);
string delKey = "AutoCache.Delete:" + baseKey;
if (_AopCache.Contains(delKey))
{
//说明此项不可缓存
flag = 2;
baseKeys.Clear();
baseKeys = null;
return null;
}
baseKeys.Add(baseKey);
}
//tables.Clear();//自己给自己造坑花了2小时才找到这坑
//tables = null;
}
if (baseKeys.Count == 0)
{
flag = 1;
}
return baseKeys;
}
private static string GetKey(AopEnum action, AopInfo aopInfo)
{
return GetKey(action, aopInfo, GetBaseKey(aopInfo));
}
private static string GetKey(AopEnum action, AopInfo aopInfo, string baseKey)
{
StringBuilder sb = new StringBuilder();
sb.Append(baseKey);
switch (action)
{
case AopEnum.ExeNonQuery:
case AopEnum.Insert:
case AopEnum.Update:
case AopEnum.Delete:
return sb.ToString();
}
#region Key1DBType
if (aopInfo.DBParameters != null && aopInfo.DBParameters.Count > 0)
{
foreach (DbParameter item in aopInfo.DBParameters)
{
sb.Append(item.ParameterName);
sb.Append(item.Value);
}
}
if (aopInfo.CustomDbPara != null)
{
foreach (AopCustomDbPara item in aopInfo.CustomDbPara)
{
sb.Append(item.ParaName);
sb.Append(item.Value);
}
}
if (aopInfo.SelectColumns != null)
{
foreach (object item in aopInfo.SelectColumns)
{
sb.Append(item);
sb.Append(item);
}
}
#endregion
switch (action)
{
case AopEnum.ExeMDataTableList:
case AopEnum.ExeScalar:
sb.Append(aopInfo.IsProc);
sb.Append(aopInfo.ProcName);
sb.Append(".");
sb.Append(action);
break;
case AopEnum.ExeMDataTable:
case AopEnum.ExeList:
case AopEnum.ExeJson:
sb.Append(aopInfo.IsProc);
sb.Append(aopInfo.ProcName);
sb.Append(".ExeTable");
break;
case AopEnum.Exists:
case AopEnum.Fill:
case AopEnum.GetCount:
sb.Append(action);
sb.Append(aopInfo.TableName);
sb.Append(aopInfo.Where);
sb.Append(".");
sb.Append(action);
break;
case AopEnum.Select:
case AopEnum.SelectList:
case AopEnum.SelectJson:
sb.Append(aopInfo.TableName);
sb.Append(aopInfo.PageIndex);
sb.Append(aopInfo.PageSize);
sb.Append(aopInfo.Where);
sb.Append(".Select");
break;
}
return StaticTool.GetHashKey(sb.ToString().ToLower());
}
private static List<string> GetRelationTables(AopInfo para)
{
List<string> tables = null;
if (para.MAction != null)
{
tables = para.MAction.Data.Columns.RelationTables;
}
else if (para.MProc != null && !para.IsProc)
{
if (para.Table != null)
{
tables = para.Table.Columns.RelationTables;
}
else
{
tables = SqlFormat.GetTableNamesFromSql(para.ProcName);
}
}
return tables;
}
#endregion
class KeyTable
{
public const string KeyTableName = "SysAutoCache";
public static bool HasAutoCacheTable = false;
public static bool CheckSysAutoCacheTable()
{
if (!HasAutoCacheTable && !string.IsNullOrEmpty(AppConfig.AutoCache.Conn))
{
string AutoCacheConn = AppConfig.AutoCache.Conn;
if (DBTool.TestConn(AutoCacheConn))
{
HasAutoCacheTable = DBTool.Exists(KeyTableName, AutoCacheConn);
//检测数据是否存在表
if (!HasAutoCacheTable)
{
MDataColumn mdc = new MDataColumn();
mdc.Add("CacheKey", System.Data.SqlDbType.NVarChar, false, false, 200, true, null);
mdc.Add("CacheTime", System.Data.SqlDbType.BigInt, false, false, -1);
HasAutoCacheTable = DBTool.CreateTable(KeyTableName, mdc, AutoCacheConn);
if (!HasAutoCacheTable)//若创建失败,可能并发下其它进程创建了。
{
HasAutoCacheTable = DBTool.Exists(KeyTableName, AutoCacheConn);//重新检测表是否存在。
}
}
}
}
return HasAutoCacheTable;
}
private static MAction _ActionInstance;
/// <summary>
/// 使用同一个链接,并且不关闭。
/// </summary>
public static MAction ActionInstance
{
get
{
if (_ActionInstance == null)
{
_ActionInstance = new MAction(KeyTableName, AppConfig.AutoCache.Conn);
_ActionInstance.SetAopState(AopOp.CloseAll);//关掉自动缓存和Aop
_ActionInstance.dalHelper.IsWriteLogOnError = false;
}
return _ActionInstance;
}
}
public static void SetKey(string key)
{
MAction action = ActionInstance;//
if (action.Exists(key))//更新时间
{
action.Set(1, DateTime.Now.ToString("yyyyMMddHHmmssfff"));
action.Update(key);
}
else
{
action.Set(0, key);
action.Set(1, DateTime.Now.ToString("yyyyMMddHHmmssfff"));
action.AllowInsertID = true;
action.Insert(InsertOp.None);
}
}
public static string keyTime = DateTime.Now.ToString("yyyyMMddHHmmssfff");
public static void ReadAndRemoveKey()
{
MAction action = ActionInstance;//
string cacheTime = DBTool.Keyword("CacheTime", action.DataBaseType);
MDataTable dt = action.Select(cacheTime + ">" + keyTime + " order by " + cacheTime + " asc");
if (dt.Rows.Count > 0)
{
foreach (MDataRow row in dt.Rows)
{
RemoveCache(row.Get<string>(0));//移除。
}
keyTime = dt.Rows[dt.Rows.Count - 1].Get<string>(1);//将时间重置为为最后一次最大的时间。
}
}
}
/*
#region
/// <summary>
/// 单例
/// </summary>
public static AutoCache Instance
{
get
{
return Shell.instance;
}
}
class Shell
{
internal static readonly AutoCache instance = new AutoCache();
}
internal AutoCache()
{
}
#endregion
*/
}
/// <summary>
/// 线程任务
/// </summary>
internal static partial class AopCache
{
static AopCache()
{
ThreadBreak.AddGlobalThread(new ParameterizedThreadStart(ClearCache));
}
#region Cache机制
//根据移除的频率,控制该项缓存的存在。
//此缓存算法,后续增加
private static Queue<string> removeList = new Queue<string>();
private static Queue<string> removeListForKeyTask = new Queue<string>();
public static void ReadyForRemove(string baseKey)
{
string delKey = "AutoCache.Delete:" + baseKey;
if (!_AopCache.Contains(delKey))
{
if (!removeList.Contains(baseKey))
{
try
{
removeList.Enqueue(baseKey);
}
catch
{
}
}
}
_AopCache.Set(delKey, 0, 0.1);//设置6秒时间
}
public static void ClearCache(object threadID)
{
try
{
System.Diagnostics.Debug.WriteLine("AutoCache.ClearCache on Thread :" + threadID);
while (true)
{
Thread.Sleep(5);
if (!KeyTable.HasAutoCacheTable && KeyTable.CheckSysAutoCacheTable())//检测并创建表放在循环中是因为可能在代码中延后会AppConifg.Cache.AutoCacheConn赋值;
{
ThreadBreak.AddGlobalThread(new ParameterizedThreadStart(AutoCacheKeyTask));//将数据库检测独立一个线程,不影响此内存操作。
}
if (removeList.Count > 0)
{
string baseKey = removeList.Dequeue();
if (!string.IsNullOrEmpty(baseKey))
{
RemoveCache(baseKey);
if (KeyTable.HasAutoCacheTable)//检测是否开启AutoCacheConn数据库链接
{
removeListForKeyTask.Enqueue(baseKey);
}
}
}
}
}
catch
{
}
}
public static void AutoCacheKeyTask(object threadID)
{
System.Diagnostics.Debug.WriteLine("AutoCache.AutoCacheKeyTask on Thread :" + threadID);
while (true)//定时扫描数据库
{
int time = AppConfig.AutoCache.TaskTime;
if (time <= 0)
{
time = 1000;
}
Thread.Sleep(time);
if (removeListForKeyTask.Count > 0)
{
string baseKey = removeListForKeyTask.Dequeue();
if (!string.IsNullOrEmpty(baseKey))
{
KeyTable.SetKey(baseKey);
}
}
if (KeyTable.HasAutoCacheTable) //读取看有没有需要移除的键。
{
KeyTable.ReadAndRemoveKey();
}
}
}
private static readonly object lockObj = new object();
private static DateTime errTime = DateTime.MinValue;
internal static void RemoveCache(string baseKey)
{
try
{
lock (lockObj)
{
string keys = string.Empty;
if (_AopCache.CacheType == CacheType.LocalCache)
{
if (cacheKeys.ContainsKey(baseKey))
{
keys = cacheKeys[baseKey].ToString();
cacheKeys.Remove(baseKey);
}
}
else
{
keys = _AopCache.Get<string>(baseKey);
}
if (!string.IsNullOrEmpty(keys))
{
foreach (string item in keys.Split(','))
{
if (string.IsNullOrEmpty(item)) { continue; }
_AopCache.Remove(item);
}
}
}
}
catch (ThreadAbortException e)
{
}
catch (OutOfMemoryException)
{ }
catch (Exception err)
{
if (errTime == DateTime.MinValue || errTime.AddMinutes(10) < DateTime.Now) // 10分钟记录一次
{
errTime = DateTime.Now;
Log.Write(err, LogType.Cache);
}
}
}
#endregion
}
}