中跨库事务管理技术方案

作者: 澳门新萄京app  发布:2019-10-17

  近来新接手了一项职业,当中有二个主意,须求对事情表展开写入数据,之后记录到日志表中。那部分代码原先是先行者写的,他不曾行使此外方案,只是简短的调用Ado.net实践了一次写库操作。由此平常出现系统使用者不断发邮件说多少有毛病,经过查阅原因就是在于写库操作中,有有些表写入退步,可是任何表写入成功,导致现身了数额分歧样的标题。后来本想改用事务,但意识日志表和事务表不在同贰个数据库下,以至不在同一个IP下,对于这么些标题,笔者想到了有以下建设方案。

由ado.net管理的业务改为团结手动提交业务和Commit恐怕RollBack操作:

step1:根据连接字符串和sql分类,存入Dictionary<string,string>中,Key为一而再字符串,Value为针对此数据库的Sql语句,多条用分号隔离;

step2:遍历此Dictionary,张开这么些连接;

step3:对于每一个连接,展开专门的学业;

step4:实践针对每种连接的sql,出现错误则全体rollback,不然全部commit;

step5:关闭连接,记录运增势况,记录日志。

现实代码如下:

  1         //提交事务用的sql
  2         public const string MultiTran = @"BEGIN TRAN
  3                                             {0}";
  4 
  5         /// <summary>
  6         /// 事务返回的信息
  7         /// </summary>
  8         public struct TransInfo
  9         {
 10             /// <summary>
 11             /// sql总条数
 12             /// </summary>
 13             public int Total;
 14             /// <summary>
 15             /// 事务执行是否成功
 16             /// </summary>
 17             public bool IsSuccess;
 18             /// <summary>
 19             /// 失败时的sql
 20             /// </summary>
 21             public string WrongMessage;
 22         }        
 23 
 24         /// <summary>
 25         /// 跨库事务异常对象
 26         /// </summary>
 27         public class TransException : Exception
 28         {
 29             public TransException(string message) : base(message)
 30             {
 31             }
 32 
 33             public string wrongSQL { get; set; }
 34             public string wrongAt { get; set; }
 35             /// <summary>
 36             /// 已经打开的连接
 37             /// </summary>
 38             public List<SqlConnection> DoneConnection = new List<SqlConnection>();
 39             /// <summary>
 40             /// 出现错误的连接
 41             /// </summary>
 42             public SqlConnection CurrentConnection;
 43             /// <summary>
 44             /// 覆盖Exception中的Message字段,使其可写
 45             /// </summary>
 46             public new string Message { get; set; }
 47         }
 48 
 49         /// <summary>
 50         /// 多操作sql,使用事务,用于多库事务
 51         /// <para>
 52         /// 返回值TransInfo字段:IsSuccess 是否成功,
 53         /// Total sql总条数,
 54         /// WrongAt 失败的sql语句
 55         /// </para>
 56         /// </summary>
 57         /// <param name="sqlwithconn">执行的sql和连接字符串列表key:sql,value:连接字符串</param>
 58         /// <param name="connectionString">连接字符串</param>
 59         /// <returns>sadf</returns>
 60         public static TransInfo RunSqlInTrans(Dictionary<string, string> sqlwithconn)
 61         {
 62             var sqltable = new Dictionary<string, string>();
 63             var conntable = new Dictionary<string, SqlConnection>();
 64 
 65             foreach (var i in sqlwithconn)
 66             {
 67                 if (!sqltable.Keys.Contains(i.Value))
 68                 {
 69                     sqltable.Add(i.Value, i.Key); //sqltable的key是连接字符串,value是sql语句
 70                     conntable.Add(i.Value, new SqlConnection(i.Value));    //key是连接字符串,value是连接对象
 71                 }
 72                 else
 73                 {
 74                     sqltable[i.Value] += ";" + i.Key;
 75                 }
 76             }
 77 
 78             try
 79             {
 80                 var wrongEx = new TransException("");
 81                 foreach (var i in sqltable)
 82                 {
 83                     //遵照晚开早关原则,在此处打开数据库连接
 84                     conntable[i.Key].Open();
 85                     //连接打开后,将连接对象放入异常处理对象中做记录
 86                     wrongEx.DoneConnection.Add(conntable[i.Key]);
 87                     var dc = new SqlCommand(string.Format(MultiTran, i.Value), conntable[i.Key]);
 88                     try
 89                     {
 90                         dc.ExecuteNonQuery();
 91                     }
 92                     catch (Exception ex)
 93                     {
 94                         //出现异常,抛出异常处理对象
 95                         wrongEx.CurrentConnection = conntable[i.Key];
 96                         wrongEx.wrongAt = i.Key;
 97                         wrongEx.wrongSQL = sqltable[i.Key];
 98                         wrongEx.Message = ex.Message;
 99                         throw wrongEx;
100                     }
101                 }
102                 //全部执行完毕没有发现错误,提交事务
103                 foreach (var i in conntable)
104                 {
105                     var dc = new SqlCommand("COMMIT TRAN", i.Value);
106                     dc.ExecuteNonQuery();
107                     i.Value.Close();
108                 }
109                 return new TransInfo()
110                 {
111                     IsSuccess = true,
112                     Total = sqlwithconn.Count,
113                     WrongMessage = ""
114                 };
115 
116             }
117             catch (TransException e)   //1.回滚所有操作2.关闭所有已经打开的数据库连接4.生成错误对象
118             {
119                 foreach (var i in e.DoneConnection)
120                 {
121                     if (!i.Equals(e.CurrentConnection))
122                     {
123                         var dc = new SqlCommand("ROLLBACK TRAN", i);
124                         dc.ExecuteNonQuery();
125                     }
126                     i.Close();
127                 }
128                 return new TransInfo()
129                 {
130                     IsSuccess = false,
131                     Total = sqlwithconn.Count,
132                     WrongMessage = string.Format("在连接{0}中,操作{1}出现错误,错误信息:{2}", e.wrongAt, e.wrongSQL, e.Message)
133                 };
134             }
135         }

 那样消除了跨库数据表管理一时因为网络难题或别的有的时候性难题变成的数码不相同样的难题。不过那么些技术方案最大的主题素材固然在意品质难点上,比方尽管有四个库若是为A,B,C,D,当中C库的数据修改写入相比较复杂,那么在A,B库开启事务后,必需等待C和D库完结或破产后,事务才得以了结,连接本领自由,那年,A库和B库正是高居挂起状态,倘诺处在高IO的生产条件中的话,那本性子的损失或者是沉重的,所以那几个方案不得不用来简单的sql管理,而且管理sql不能够太多或然太复杂。况兼现身网络波动的话,损失会更加大。幸运的是自身所接手的那些专门的学业,是在内网情形中,同一时间只用两句sql在多个库中,所以用这些方案难题非常的小。

小结:针对那一个主题素材,小编觉妥贴初统一盘算数据库时,能制止跨库就绝对要制止。

比方大家有何样更加好的缓慢解决方案以来,希望和豪门多多沟通和指教。

 

本文由澳门新萄京app发布于澳门新萄京app,转载请注明出处:中跨库事务管理技术方案

关键词:

上一篇:API函数大全
下一篇:没有了