using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Web;
using CYQ.Data.Tool;
namespace CYQ.Data
{
///
/// 一个数据库对像实例:集合了主从备三种
///
internal partial class ConnObject
{
public ConnBean Master;
public ConnBean BackUp;
public MList Slave = new MList();
///
/// 主备互换位置。
///
internal void InterChange()
{
if (BackUp != null)
{
ConnBean middle = Master;
Master = BackUp;
BackUp = middle;
}
}
static int index = -1;
static readonly object o = new object();
public ConnBean GetSlave()
{
if (Slave.Count > 0)
{
lock (o)
{
if (index == -1)
{
index = new Random().Next(Slave.Count);
}
if (index >= Slave.Count)//2
{
index = 0;
}
ConnBean slaveBean = Slave[index];
index++;
if (slaveBean.IsOK)//链接正常,则返回。
{
return slaveBean;
}
else if (Slave.Count > 1)
{
//int i = index + 1;//尝试一下个,。
for (int i = index + 1; i < Slave.Count + 1; i++)
{
if (i == Slave.Count)
{
i = 0;
}
if (i == index) { break; }
if (Slave[i].IsOK)
{
return Slave[i];
}
}
}
//从全部挂了,返回主
if (Master != null && Master.IsOK)
{
return Master;
}
else if (BackUp != null && BackUp.IsOK)
{
return BackUp;
}
}
}
return null;
}
///
/// 设置临时仅允许访问主库(默认10秒)
///
public void SetFocusOnMaster()
{
if (Slave.Count > 0)
{
string id = StaticTool.GetMasterSlaveKey();//获取当前的标识
Cache.DistributedCache.Local.Set(id, 1, AppConfig.DB.MasterSlaveTime / 60.0);
}
}
public bool IsAllowSlave()
{
if (Slave.Count == 0) { return false; }
string id = StaticTool.GetMasterSlaveKey();//获取当前的标识
return !Cache.DistributedCache.Local.Contains(id);
}
}
internal partial class ConnObject
{
///
/// 所有链接的对象集合
///
private static MDictionary connDicCache = new MDictionary(StringComparer.OrdinalIgnoreCase);
internal static ConnObject Create(string connNameOrString)
{
connNameOrString = string.IsNullOrEmpty(connNameOrString) ? AppConfig.DB.DefaultConn : connNameOrString;
if (connNameOrString.EndsWith("_Bak"))
{
connNameOrString = connNameOrString.Replace("_Bak", "");
}
if (connDicCache.ContainsKey(connNameOrString))
{
return connDicCache[connNameOrString];
}
ConnBean cbMaster = ConnBean.Create(connNameOrString);
if (cbMaster == null)
{
#region 重试读取默认Conn配置
string errMsg = string.Format("Can't find the connection key '{0}' from connectionStrings config section !", connNameOrString);
if (connNameOrString == AppConfig.DB.DefaultConn)
{
Error.Throw(errMsg);
}
else
{
ConnBean cb = ConnBean.Create(AppConfig.DB.DefaultConn); // 这里切到了默认链接,导致ConnName变成了默认
if (cb != null)
{
cbMaster = cb.Clone();//获取默认的值。
}
else
{
Error.Throw(errMsg);
}
}
#endregion
}
ConnObject co = new ConnObject();
co.Master = cbMaster;
#region 加载主从备节点
if (connNameOrString != null && connNameOrString.Length < 32 && !connNameOrString.Trim().Contains(" ")) // 为configKey
{
ConnBean coBak = ConnBean.Create(connNameOrString + "_Bak");
if (coBak != null && coBak.ConnDataBaseType == cbMaster.ConnDataBaseType)
{
co.BackUp = coBak;
co.BackUp.IsBackup = true;
}
for (int i = 1; i < 10000; i++)
{
ConnBean cbSlave = ConnBean.Create(connNameOrString + "_Slave" + i);
if (cbSlave == null)
{
break;
}
cbSlave.IsSlave = true;
co.Slave.Add(cbSlave);
}
}
#endregion
if (!connDicCache.ContainsKey(connNameOrString) && co.Master.ConnName == connNameOrString) // 非一致的,由外面切换后再缓存
{
connDicCache.Set(connNameOrString, co);
}
return co;
}
public void SaveToCache(string key)
{
if (!connDicCache.ContainsKey(key))
{
connDicCache.Add(key, this);
}
}
public static void Clear()
{
connDicCache.Clear();
}
public static void Remove(string key)
{
connDicCache.Remove(key);
}
}
///
/// 线程任务
///
internal partial class ConnObject
{
static ConnObject()
{
ThreadBreak.AddGlobalThread(new ParameterizedThreadStart(CheckConnIsOk));//主从链接的检测机制。
}
///
/// 定时检测异常的链接是否恢复。
///
///
public static void CheckConnIsOk(object threadID)
{
System.Diagnostics.Debug.WriteLine("ConnObject.CheckConnIsOk on Thread :" + threadID);
while (true)
{
Thread.Sleep(1000);
if (connDicCache.Count > 0)
{
try
{
string[] items = new string[connDicCache.Count];
connDicCache.Keys.CopyTo(items, 0);
foreach (string key in items)
{
ConnObject obj = connDicCache[key];
if (obj != null)
{
if (!obj.Master.IsOK)
{
if (obj.Master.ConnName == obj.Master.ConnString)
{
connDicCache.Remove(key);//移除错误的链接。
continue;
}
obj.Master.TryTestConn();
}
if (obj.BackUp != null && !obj.BackUp.IsOK) { obj.BackUp.TryTestConn(); }
if (obj.Slave != null && obj.Slave.Count > 0)
{
for (int i = 0; i < obj.Slave.Count; i++)
{
if (!obj.Slave[i].IsOK)
{
obj.Slave[i].TryTestConn();
}
}
}
}
}
items = null;
}
catch
{
}
}
}
}
}
}