diff --git a/Action/MAction.cs b/Action/MAction.cs index 15b1a268..c1d29547 100644 --- a/Action/MAction.cs +++ b/Action/MAction.cs @@ -177,6 +177,16 @@ public int RecordsAffected } } /// + /// 是否事务进行中 + /// + public bool IsTransation + { + get + { + return dalHelper.IsOpenTrans; + } + } + /// /// Command Timeout[seconds] ///命令超时设置[单位秒] /// diff --git a/Action/MProc.cs b/Action/MProc.cs index 77da4d73..55a2df35 100644 --- a/Action/MProc.cs +++ b/Action/MProc.cs @@ -127,6 +127,16 @@ public int RecordsAffected } } /// + /// 鏄惁浜嬪姟杩涜涓 + /// + public bool IsTransation + { + get + { + return dalHelper.IsOpenTrans; + } + } + /// /// The database connection string ///鏁版嵁搴撻摼鎺ュ瓧绗︿覆 /// diff --git a/DAL/Conn/ConnObject.cs b/DAL/Conn/ConnObject.cs index 5acbcdc2..6eb5c637 100644 --- a/DAL/Conn/ConnObject.cs +++ b/DAL/Conn/ConnObject.cs @@ -85,59 +85,17 @@ public void SetFocusOnMaster() { if (Slave.Count > 0) { - string id = GetIdentity();//获取当前的标识 + string id = StaticTool.GetMasterSlaveKey();//获取当前的标识 Cache.CacheManage.LocalInstance.Set(id, 1, AppConfig.DB.MasterSlaveTime / 60.0); } } public bool IsAllowSlave() { if (Slave.Count == 0) { return false; } - string id = GetIdentity();//获取当前的标识 + string id = StaticTool.GetMasterSlaveKey();//获取当前的标识 return !Cache.CacheManage.LocalInstance.Contains(id); } - private string GetIdentity() - { - string id = string.Empty; - if (HttpContext.Current != null) - { - if (HttpContext.Current.Session != null) - { - id = HttpContext.Current.Session.SessionID; - } - else if (HttpContext.Current.Request["Token"] != null) - { - id = HttpContext.Current.Request["Token"]; - } - else if (HttpContext.Current.Request.Headers["Token"] != null) - { - id = HttpContext.Current.Request.Headers["Token"]; - } - else if (HttpContext.Current.Request["MasterSlaveid"] != null) - { - id = HttpContext.Current.Request["MasterSlaveid"]; - } - if (string.IsNullOrEmpty(id)) - { - HttpCookie cookie = HttpContext.Current.Request.Cookies["MasterSlaveid"]; - if (cookie != null) - { - id = cookie.Value; - } - else - { - id = Guid.NewGuid().ToString().Replace("-", ""); - cookie = new HttpCookie("MasterSlaveid", id); - cookie.Expires = DateTime.Now.AddMonths(1); - HttpContext.Current.Response.Cookies.Add(cookie); - } - } - } - if (string.IsNullOrEmpty(id)) - { - id = DateTime.Now.Minute + Thread.CurrentThread.ManagedThreadId.ToString(); - } - return "MasterSlave_" + id; - } + } internal partial class ConnObject @@ -242,14 +200,14 @@ public static void CheckConnIsOk(object threadid) ConnObject obj = connDicCache[key]; if (obj != null) { - if (!obj.Master.IsOK) + if (!obj.Master.IsOK) { if (obj.Master.ConnName == obj.Master.ConnString) { connDicCache.Remove(key);//移除错误的链接。 continue; } - obj.Master.TryTestConn(); + obj.Master.TryTestConn(); } if (obj.BackUp != null && !obj.BackUp.IsOK) { obj.BackUp.TryTestConn(); } if (obj.Slave != null && obj.Slave.Count > 0) diff --git a/DAL/DalBase.cs b/DAL/DalBase.cs index ca4a7c85..825c1fcf 100644 --- a/DAL/DalBase.cs +++ b/DAL/DalBase.cs @@ -7,6 +7,7 @@ using CYQ.Data.Tool; using System.Data.SqlTypes; using System.Threading; +using CYQ.Data.Orm; namespace CYQ.Data @@ -478,6 +479,10 @@ public virtual bool AddParameters(string parameterName, object value, DbType dbT { parameterName = parameterName.Substring(0, 1) == Pre.ToString() ? parameterName : Pre + parameterName; } + if (Com == null) + { + return false; + } if (Com.Parameters.Contains(parameterName))//宸茬粡瀛樺湪锛屼笉娣诲姞 { return false; @@ -789,6 +794,11 @@ internal void WriteError(string err) public void Dispose() { + string key = StaticTool.GetTransationKey(UsingConnBean.ConnName); + if (DBFast.HasTransation(key)) + { + return;//鍏ㄥ眬浜嬪姟鐢卞叏灞鎺у埗锛堝叏灞浜嬪姟浼氬湪绉婚櫎key鍚庨噸鏂拌皟鐢級銆 + } if (_con != null) { CloseCon(); diff --git a/DAL/DalCreate.cs b/DAL/DalCreate.cs index 9fcdc8f7..bed929d6 100644 --- a/DAL/DalCreate.cs +++ b/DAL/DalCreate.cs @@ -4,6 +4,7 @@ using CYQ.Data.Tool; using System.Threading; using System.IO; +using CYQ.Data.Orm; namespace CYQ.Data @@ -11,7 +12,7 @@ namespace CYQ.Data /// /// 数据库类型操作类 /// - internal class DalCreate + internal static class DalCreate { //private const string SqlClient = "System.Data.SqlClient"; //private const string OleDb = "System.Data.OleDb"; @@ -24,10 +25,48 @@ internal class DalCreate //private const string XmlClient = "CYQ.Data.XmlClient"; //private const string XHtmlClient = "CYQ.Data.XHtmlClient"; + /// + /// 全局存档,是为了用单例来实现全局事务。 + /// + private static MDictionary dalBaseDic = new MDictionary(); + public static DalBase Get(string key) + { + if (dalBaseDic.ContainsKey(key)) + { + return dalBaseDic[key]; + } + return null; + } + public static bool Remove(string key) + { + return dalBaseDic.Remove(key); + } /// /// 简单工厂(Factory Method) /// public static DalBase CreateDal(string connNameOrString) + { + string key = StaticTool.GetTransationKey(connNameOrString); + //检测是否开启了全局事务; + bool isTrans = DBFast.HasTransation(key); + if (isTrans) + { + if (dalBaseDic.ContainsKey(key)) + { + return dalBaseDic[key]; + } + + } + DalBase dal = CreateDalBase(connNameOrString); + if (isTrans) + { + dal.TranLevel = DBFast.GetTransationLevel(key); + dal.IsOpenTrans = true; + dalBaseDic.Add(key, dal); + } + return dal; + } + private static DalBase CreateDalBase(string connNameOrString) { //ABCConn DalBase db = GetDalBaseBy(ConnObject.Create(connNameOrString)); @@ -43,9 +82,7 @@ public static DalBase CreateDal(string connNameOrString) } } return db; - } - private static DalBase GetDalBaseBy(ConnObject co) { DataBaseType dalType = co.Master.ConnDalType; diff --git a/Orm/DBFast.cs b/Orm/DBFast.cs index ceb2892c..4483eef2 100644 --- a/Orm/DBFast.cs +++ b/Orm/DBFast.cs @@ -4,6 +4,9 @@ using CYQ.Data.Table; using CYQ.Data.SQL; using CYQ.Data.Tool; +using System.Web; +using System.Threading; +using System.Data; namespace CYQ.Data.Orm @@ -13,6 +16,73 @@ namespace CYQ.Data.Orm /// public static class DBFast { + /// + /// 当前 用户 是否开启了全局事务 + /// + /// + internal static bool HasTransation(string key) + { + return TransationKeys.ContainsKey(key); + } + internal static IsolationLevel GetTransationLevel(string key) + { + if (TransationKeys.ContainsKey(key)) + { + return TransationKeys[key]; + } + return IsolationLevel.ReadCommitted; + } + /// + /// 存档事务的标识 + /// + public static MDictionary TransationKeys = new MDictionary(); + /// + /// 开启事务 (Web 状态下以(Session+线程ID)为单位,其它状态下仅以线程ID为单位) + /// 如果已存在事务(则返回false) + /// + public static bool BeginTransation(string conn) + { + return BeginTransation(conn, IsolationLevel.ReadCommitted); + } + public static bool BeginTransation(string conn, IsolationLevel level) + { + string key = StaticTool.GetTransationKey(conn); + if (!TransationKeys.ContainsKey(key)) + { + TransationKeys.Add(key, level); + } + return false; + } + /// + /// 提交事务 + /// + public static bool EndTransation(string conn) + { + string key = StaticTool.GetTransationKey(conn); + TransationKeys.Remove(key); + DalBase dal = DalCreate.Get(key); + if (dal != null && dal.EndTransaction())//如果事务回滚了, + { + dal.Dispose(); + return DalCreate.Remove(key); + } + return false; + } + /// + /// 事务回滚 + /// + public static bool RollBack(string conn) + { + string key = StaticTool.GetTransationKey(conn); + TransationKeys.Remove(key); + DalBase dal = DalCreate.Get(key); + if (dal != null && dal.RollBack()) + { + dal.Dispose(); + return DalCreate.Remove(key); + } + return false; + } /// /// 查找单条记录 /// diff --git a/Orm/OrmBaseInfo.cs b/Orm/OrmBaseInfo.cs index 4fcb7c73..975fecec 100644 --- a/Orm/OrmBaseInfo.cs +++ b/Orm/OrmBaseInfo.cs @@ -30,6 +30,16 @@ public int RecordsAffected } } /// + /// 鏄惁浜嬪姟杩涜涓 + /// + public bool IsTransation + { + get + { + return _Action.IsTransation; + } + } + /// /// 鑾峰彇 鏁版嵁搴撶殑 琛ㄥ悕 /// public string TableName diff --git a/Orm/SimpleOrmBase.cs b/Orm/SimpleOrmBase.cs index 1129feec..10622186 100644 --- a/Orm/SimpleOrmBase.cs +++ b/Orm/SimpleOrmBase.cs @@ -613,7 +613,7 @@ private void GetValueFromEntity() /// public void Dispose() { - if (Action != null) + if (Action != null && !Action.IsTransation)//ORM的事务,由全局控制,不在这里释放链接。 { Action.Dispose(); } diff --git a/Tool/StaticTool.cs b/Tool/StaticTool.cs index 47329fef..2dec55d3 100644 --- a/Tool/StaticTool.cs +++ b/Tool/StaticTool.cs @@ -6,6 +6,8 @@ using CYQ.Data.Table; using CYQ.Data.SQL; using System.IO; +using System.Web; +using System.Threading; namespace CYQ.Data.Tool @@ -26,11 +28,6 @@ internal static string ToGuidByteString(string guid) return BitConverter.ToString(new Guid(guid).ToByteArray()).Replace("-", ""); } - - - - - #region 将字符串变HashKey static MDictionary hashKeyCache = new MDictionary(32); internal static string GetHashKey(string sourceString) { @@ -57,7 +54,78 @@ internal static string GetHashKey(string sourceString) return sourceString; } } - #endregion - + /// + /// 用于标识(以用户为单位)的 主从 的唯一标识 + /// + /// + public static string GetMasterSlaveKey() + { + string id = string.Empty; + if (HttpContext.Current != null) + { + if (HttpContext.Current.Session != null) + { + id = HttpContext.Current.Session.SessionID; + } + else if (HttpContext.Current.Request["Token"] != null) + { + id = HttpContext.Current.Request["Token"]; + } + else if (HttpContext.Current.Request.Headers["Token"] != null) + { + id = HttpContext.Current.Request.Headers["Token"]; + } + else if (HttpContext.Current.Request["MasterSlaveid"] != null) + { + id = HttpContext.Current.Request["MasterSlaveid"]; + } + if (string.IsNullOrEmpty(id)) + { + HttpCookie cookie = HttpContext.Current.Request.Cookies["MasterSlaveid"]; + if (cookie != null) + { + id = cookie.Value; + } + else + { + id = Guid.NewGuid().ToString().Replace("-", ""); + cookie = new HttpCookie("MasterSlaveid", id); + cookie.Expires = DateTime.Now.AddMonths(1); + HttpContext.Current.Response.Cookies.Add(cookie); + } + } + } + if (string.IsNullOrEmpty(id)) + { + id = DateTime.Now.Minute + Thread.CurrentThread.ManagedThreadId.ToString(); + } + return "MasterSlave_" + id; + } + /// + /// 用于标识(以用户为单位)的 全局事务 的唯一标识 + /// + public static string GetTransationKey(string conn) + { + string key = Thread.CurrentThread.ManagedThreadId.ToString(); + if (HttpContext.Current != null) + { + string id = string.Empty; + if (HttpContext.Current.Session != null) + { + id = HttpContext.Current.Session.SessionID; + } + else if (HttpContext.Current.Request["Token"] != null) + { + id = HttpContext.Current.Request["Token"]; + } + else if (HttpContext.Current.Request.Headers["Token"] != null) + { + id = HttpContext.Current.Request.Headers["Token"]; + } + key = id + key; + } + int hash = ConnBean.GetHashCode(conn); + return "Transation_" + key + hash; + } } } diff --git "a/\346\233\264\346\226\260\350\256\260\345\275\225.txt" "b/\346\233\264\346\226\260\350\256\260\345\275\225.txt" index be26614c..1ecf95db 100644 --- "a/\346\233\264\346\226\260\350\256\260\345\275\225.txt" +++ "b/\346\233\264\346\226\260\350\256\260\345\275\225.txt" @@ -796,4 +796,5 @@ 581:NoSqlAction:文本数据库机制内部调整、查询优化。(2019-04-29) 582:Aop、AutoCache:自动缓存机制小调整,除了原有的全局IsAutoCache全局初始化控制外,Aop参数可二次强制控制。(2019-04-29) 583:增加 JsonIgnore 属性(标识不输出Json的字段)、SimpleOrmBase、OrmBase增加BaseInfo属性可获得详细信息(2019-04-29) -584:优化Json与Xml互转机制(2019-04-29) \ No newline at end of file +584:优化Json与Xml互转机制(2019-04-29) +585:DBFast 增加全局事务机制【最近因 Gemini.Workflow,因此对ORM实体这一块进行内部机制大升级】(2019-05-04) \ No newline at end of file