流水号的获取在单机版的程序中只需要简单的递增就可以解决。但是在分布式系统中存在多个客户端同时请求同一个流水号的问题,如果处理不好容易导致多个客户端获得同一个流水号。
解决方案一
在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
新闻热点
疑难解答