ZhiYeJianKang_PeiXun/cyqdata-master/Aop/AopCache.cs
2025-02-20 15:41:53 +08:00

1079 lines
40 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}
}