流水號的獲取在單機版的程序中只需要簡單的遞增就可以解決。但是在分布式系統中存在多個客戶端同時請求同一個流水號的問題,如果處理不好容易導致多個客戶端獲得同一個流水號。
解決方案一
在Oracle數據庫中有專門的序列管理sequence,具體的介紹在網上可以找到很多。但是在實際使用中存在很多的問題:
1、如果有很多個不同的序列,并且在需要根據時間變化(每天0點重置)時處理起來很麻煩。
2、隨時間增加數據庫中的序列越來越多。
3、在首次創建一個序列的時候需要激活后才能正常使用。
所以果斷放棄了這個方案。
解決方案二
大體的思路:在數據庫中專門建一個表存儲各類的序列,在服務器端創建一個服務專門提供各類序列當前的流水號??蛻舳送ㄟ^這個服務來獲取序列,不能直接去數據庫中查
第1步:在數據庫中專門創建一個新的表用來存儲這些序列。表結構如下:
1、FLAG(標志碼 主鍵):代表序列的標志
2、Sequence(當前的流水號):默認為0
3、UpdateTime(更新時間):根據自己的需要來創建
第2步:先創建一些接口
1、數據服務的接口
1 public interface IDataOperator 2 { 3 int ExecuteNonQuery(List<string> list); 4 int ExecuteNonQuery(string strSql); 5 int ExecuteNonQuery(List<string> list, ref string strError); 6 int ExecuteNonQuery(string strSql, ref string strError); 7 T ExecuteScalar<T>(string strSql); 8 T ExecuteScalar<T>(string strSql, ref string strError); 9 DataSet GetDataSet(string strSql);10 DataSet GetDataSet(string strSql, ref string strError);11 DataTable GetDataTable(string strSql);12 DataTable GetDataTable(string strSql, ref string strError);13 }View Code
2、流水號的接口
1 public interface ISequence2 {3 int GetNext(string strFlag);4 }View Code
第3步:在服務器端創建一個服務,這個服務有兩個功能。我這邊客戶端和服務端的通信用的是Remoting技術。這里就不展示相關的代碼了。
1、做客戶端的數據中轉,直接和數據庫服務器之間通信,
1 public class SqlServer : MarshalByRefObject,IDataOperator 2 { 3 #region 私有字段 4 PRivate string strConn; 5 #endregion 6 /// <summary> 7 /// 構造器 8 /// </summary> 9 public SqlServer () 10 { 11 strConn = string.Format(@"User ID={0};PassWord={1};Data Source={2};Pooling=true;Min Pool Size=0;Max Pool Size={3};", 12 “”, 13 “”, 14 “” 15 “”; 16 17 } 18 /// <summary> 19 /// 打開數據庫連接 20 /// </summary> 21 /// <param name="strError">返回錯誤信息</param> 22 /// <returns></returns> 23 public bool OpenTest(ref string strError) 24 { 25 bool blResult = false; 26 try 27 { 28 using (SqlConnection conn = new SqlConnection(strConn)) 29 { 30 conn.Open(); 31 conn.Close(); 32 } 33 blResult = true; 34 } 35 catch(Exception ex) 36 { 37 strError = ex.Message; 38 } 39 return blResult; 40 } 41 /// <summary> 42 /// 執行一個SQL語句集合返回操作成功數 43 /// </summary> 44 /// <param name="strsql"></param> 45 /// <param name="parameter"></param> 46 /// <returns></returns> 47 public int ExecuteNonQuery(List<string> list, ref string strError) 48 { 49 int intResult = 0; 50 int i = 0; 51 if (list.Count > 0) 52 { 53 try 54 { 55 using (SqlConnection conn = new SqlConnection(strConn)) 56 { 57 58 conn.Open(); 59 SqlTransaction tran = conn.BeginTransaction(); 60 61 try 62 { 63 using (SqlCommand cmd = conn.CreateCommand()) 64 { 65 cmd.Transaction = tran; 66 for (i = 0; i < list.Count; i++) 67 { 68 cmd.CommandText = list[i].Trim(); 69 intResult+= cmd.ExecuteNonQuery(); 70 } 71 tran.Commit(); 72 } 73 74 } 75 catch (Exception ex) 76 { 77 try 78 { 79 intResult = -1; 80 tran.Rollback(); 81 82 strError = 83 string.Format("{0}個操作回滾成功!{1}/r/n ErrSQL:/r/n {2}", 84 i, ex.Message, list[i]); 85 } 86 catch(Exception ex2) 87 { 88 intResult = -2; 89 strError = 90 string.Format("{0}個操作回滾失敗!{1}/r/n ErrSQL:/r/n {2}", 91 i, ex2.Message, list[i]); 92 } 93 } 94 finally 95 { 96 conn.Close(); 97 } 98 } 99 }100 catch (SqlException ex)101 {102 103 strError = ex.Message;104 }105 106 }107 else108 {109 strError = string.Format("ExecuteNonQuery(List<string> list):未傳入需要執行的SQL語句");110 }111 return intResult;112 113 }114 /// <summary>115 /// 執行一個SQL語句集合返回操作成功數116 /// </summary>117 /// <param name="strsql"></param>118 /// <param name="parameter"></param>119 /// <returns></returns>120 public int ExecuteNonQuery(List<string> list)121 {122 int intResult = 0;123 int i = 0;124 if (list.Count > 0)125 {126 using (SqlConnection conn = new SqlConnection(strConn))127 {128 conn.Open();129 SqlTransaction tran = conn.BeginTransaction();130 using (SqlCommand cmd = conn.CreateCommand())131 {132 try133 {134 cmd.Transaction = tran;135 for (i = 0; i < list.Count; i++)136 {137 cmd.CommandText = list[i].Trim(); 138 intResult += cmd.ExecuteNonQuery();139
新聞熱點
疑難解答