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