自定義個“緩存數據庫”玩玩


前言:首先聲明,此文題目算是標題黨的一種,是本人為了完成與widows服務通信編程學習幻想出來的一個模型(並不是真的緩存數據庫),並且會作為本人以后加深多線程、設計模式、非關系型數據庫等方面學習的一個模型實例,畢竟有一個實際的模型更容易加深理解。

完成這部分模型,大概會做一下幾件事情:

1、  創建一個Windows服務(用來寄存這個“緩存數據庫”)

2、  創建一個WCF服務,寄宿在windows服務中(用於跟客戶端通信,對“緩存數據庫”進行增刪查操作)

3、  創建客戶端進行測試

第1步:WCF服務的創建及對緩存對象增刪查的實現

WCF服務創建的過程及其Endpoint節點相關基礎在這里不作累述,網上很多資料,這里直接貼Contract及其實現的代碼,保存表數據的數據結構是Dictionary<string,DataTable>,其中key存放是表名,DataTable存放是數據。

 1 using System;
 2 
 3 using System.Collections.Generic;
 4 
 5 using System.Data;
 6 
 7 using System.Linq;
 8 
 9 using System.Runtime.Serialization;
10 
11 using System.ServiceModel;
12 
13 using System.ServiceModel.Web;
14 
15 using System.Text;
16 
17  
18 
19 namespace SelfWcfService
20 
21 {
22 
23     // 注意: 使用“重構”菜單上的“重命名”命令,可以同時更改代碼和配置文件中的接口名“IService1”。
24 
25     [ServiceContract]
26 
27     public interface ISelfSQLData
28 
29     {
30 
31         [OperationContract]
32 
33         ExcuteResult CreateTable(string tableName, DataTable colNames);
34 
35  
36 
37         [OperationContract]
38 
39         ExcuteResult Insert(string tableName, SelfDataRow dr);
40 
41  
42 
43         [OperationContract]
44 
45         ExcuteResult Delete(string tableName, SelfDataRow dr);
46 
47  
48 
49         [OperationContract]
50 
51         ExcuteResult DropTable(string tableName);
52 
53  
54 
55         [OperationContract]
56 
57         Dictionary<string, DataTable> GetData();       
58 
59     }
60 
61  
62 
63     [DataContract]
64 
65     public class SQLData
66 
67     {
68 
69         [DataMember]
70 
71         public Dictionary<string, DataTable> DataTables { get; set; }       
72 
73     }
74 
75    
76 
77     [DataContract]
78 
79     public class SelfDataRow
80 
81     {
82 
83         [DataMember]
84 
85         public DataTable DataTable { get; set; }
86 
87     }
88 
89 }

接口實現部分:

 

  1 using System;
  2 
  3 using System.Collections.Generic;
  4 
  5 using System.Data;
  6 
  7 using System.Linq;
  8 
  9 using System.Runtime.Serialization;
 10 
 11 using System.ServiceModel;
 12 
 13 using System.ServiceModel.Web;
 14 
 15 using System.Text;
 16 
 17  
 18 
 19 namespace SelfWcfService
 20 
 21 {
 22 
 23     // 注意: 使用“重構”菜單上的“重命名”命令,可以同時更改代碼、svc 和配置文件中的類名“Service1”。
 24 
 25     // 注意: 為了啟動 WCF 測試客戶端以測試此服務,請在解決方案資源管理器中選擇 Service1.svc 或 Service1.svc.cs,然后開始調試。
 26 
 27     public class SelfSQLData : ISelfSQLData
 28 
 29     {
 30 
 31         private static SQLData _sqlData;
 32 
 33         public static SQLData SqlData
 34 
 35         {
 36 
 37             get
 38 
 39             {
 40 
 41                 if (_sqlData == null)
 42 
 43                 {
 44 
 45                     _sqlData = new SQLData();
 46 
 47                 }
 48 
 49                 if (_sqlData.DataTables == null)
 50 
 51                 {
 52 
 53                     _sqlData.DataTables = new Dictionary<string, System.Data.DataTable>();
 54 
 55                 }
 56 
 57                 return _sqlData;
 58 
 59             }
 60 
 61             set
 62 
 63             {
 64 
 65                 _sqlData = value;
 66 
 67             }
 68 
 69         }
 70 
 71  
 72 
 73         private void InitalSqlData()
 74 
 75         {
 76 
 77             if (_sqlData == null)
 78 
 79             {
 80 
 81                 _sqlData = new SQLData();
 82 
 83             }
 84 
 85             if (_sqlData.DataTables == null)
 86 
 87             {
 88 
 89                 _sqlData.DataTables = new Dictionary<string, System.Data.DataTable>();
 90 
 91             }
 92 
 93         }
 94 
 95  
 96 
 97         public ExcuteResult CreateTable(string tableName, DataTable colNames)
 98 
 99         {
100 
101             if (string.IsNullOrWhiteSpace(tableName))
102 
103             {
104 
105                 return new ExcuteResult(1, "表名不能為空!");
106 
107             }
108 
109             if (colNames == null || colNames.Columns.Count < 1)
110 
111             {
112 
113                 return new ExcuteResult(1, "表字段不能為空!");
114 
115             }
116 
117             InitalSqlData();
118 
119             if (!_sqlData.DataTables.ContainsKey(tableName))
120 
121             {
122 
123                 try
124 
125                 {
126 
127                     _sqlData.DataTables.Add(tableName, colNames);
128 
129                 }
130 
131                 catch (Exception ex)
132 
133                 {
134 
135                     return new ExcuteResult(1, ex.Message);
136 
137                 }
138 
139                 return new ExcuteResult(0, "" + tableName + "創建成功!");
140 
141             }
142 
143             else
144 
145             {
146 
147                 return new ExcuteResult(1, "已存在名為'" + tableName + "'的表");
148 
149             }
150 
151         }
152 
153  
154 
155         public ExcuteResult Insert(string tableName, SelfDataRow dr)
156 
157         {
158 
159             if (string.IsNullOrWhiteSpace(tableName))
160 
161             {
162 
163                 return new ExcuteResult(1, "表名不能為空!");
164 
165             }
166 
167             if (dr == null)
168 
169             {
170 
171                 return new ExcuteResult(1, "不能插入空的數據行!");
172 
173             }
174 
175             InitalSqlData();
176 
177             if (!_sqlData.DataTables.ContainsKey(tableName))
178 
179             {
180 
181                 try
182 
183                 {
184 
185                     _sqlData.DataTables[tableName].Rows.Add(dr.DataTable.Rows[0]);
186 
187                 }
188 
189                 catch (Exception ex)
190 
191                 {
192 
193                     return new ExcuteResult(1, ex.Message);
194 
195                 }
196 
197                 return new ExcuteResult(0, "數據新增成功!");
198 
199             }
200 
201             else
202 
203             {
204 
205                 return new ExcuteResult(1, "表'" + tableName + "'不存在!");
206 
207             }
208 
209         }
210 
211  
212 
213         public ExcuteResult Delete(string tableName, SelfDataRow dr)
214 
215         {
216 
217             if (string.IsNullOrWhiteSpace(tableName))
218 
219             {
220 
221                 return new ExcuteResult(1, "表名不能為空!");
222 
223             }
224 
225             if (dr == null)
226 
227             {
228 
229                 return new ExcuteResult(1, "請指定刪除對象!");
230 
231             }
232 
233             InitalSqlData();
234 
235             if (!_sqlData.DataTables.ContainsKey(tableName))
236 
237             {
238 
239                 try
240 
241                 {
242 
243                     _sqlData.DataTables[tableName].Rows.Remove(dr.DataTable.Rows[0]);
244 
245                 }
246 
247                 catch (Exception ex)
248 
249                 {
250 
251                     return new ExcuteResult(1, ex.Message);
252 
253                 }
254 
255                 return new ExcuteResult(0, "數據刪除成功!");
256 
257             }
258 
259             else
260 
261             {
262 
263                 return new ExcuteResult(1, "表'" + tableName + "'不存在!");
264 
265             }
266 
267         }
268 
269  
270 
271         public ExcuteResult DropTable(string tableName)
272 
273         {
274 
275             if (string.IsNullOrWhiteSpace(tableName))
276 
277             {
278 
279                 return new ExcuteResult(1, "表名不能為空!");
280 
281             }
282 
283             InitalSqlData();
284 
285             if (!_sqlData.DataTables.ContainsKey(tableName))
286 
287             {
288 
289                 try
290 
291                 {
292 
293                     _sqlData.DataTables.Remove(tableName);
294 
295                 }
296 
297                 catch (Exception ex)
298 
299                 {
300 
301                     return new ExcuteResult(1, ex.Message);
302 
303                 }
304 
305                 return new ExcuteResult(0, "" + tableName + "刪除成功!");
306 
307             }
308 
309             else
310 
311             {
312 
313                 return new ExcuteResult(1, "表'" + tableName + "'不存在!");
314 
315             }
316 
317         }
318 
319  
320 
321         public Dictionary<string, DataTable> GetData()
322 
323         {
324 
325             return SqlData.DataTables;
326 
327         }
328 
329     }
330 
331 }

 

整個WCF實現的邏輯都在上面了,web配置文件不需要改,因為它不以web的形式發布寄宿在IIS中,而是windows服務中。

第2步:將WCF寄宿在Windows服務中

Windows服務的創建、安裝、啟動在這里也不作累述,跟WCF一樣,網上資料也很多。這里重點介紹一下將WCF寄宿在Windows服務中。

(1)       將wcf項目的dll引用到windows服務項目中

 

 

(2)       在app.config文件中配置WCF終結點

 1 <system.serviceModel>
 2 
 3     <services>
 4 
 5       <service behaviorConfiguration="BasicServiceBehavior"
 6 
 7         name="SelfWcfService.SelfSQLData">
 8 
 9         <endpoint address="" binding="netTcpBinding" bindingConfiguration=""
10 
11           contract="SelfWcfService.ISelfSQLData">
12 
13           <!--<identity>
14 
15             <dns value="192.168.1.4" />
16 
17           </identity>-->
18 
19         </endpoint>
20 
21         <endpoint address="mex" binding="mexTcpBinding" bindingConfiguration=""
22 
23           contract="IMetadataExchange" />
24 
25         <host>
26 
27           <baseAddresses>
28 
29             <add baseAddress="net.tcp://localhost:9000/SelfSQLData.svc"/>
30 
31             <add baseAddress="http://localhost:9001/SelfSQLData.svc"/>
32 
33           </baseAddresses>
34 
35         </host>
36 
37       </service>
38 
39     </services>
40 
41     <behaviors>
42 
43       <serviceBehaviors>
44 
45         <behavior name="BasicServiceBehavior">
46 
47           <serviceMetadata httpGetEnabled="true" />
48 
49           <serviceDebug includeExceptionDetailInFaults="true" />
50 
51         </behavior>
52 
53       </serviceBehaviors>
54 
55     </behaviors>
56 
57     <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" minFreeMemoryPercentageToActivateService="0" />
58 
59     <bindings>
60 
61       <netTcpBinding>
62 
63         <binding name="defaultBinding" maxBufferSize="2147483647" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647">
64 
65           <security mode="None">
66 
67             <message clientCredentialType="None"/>
68 
69             <transport clientCredentialType="None"></transport>
70 
71           </security>
72 
73           <readerQuotas />
74 
75         </binding>
76 
77       </netTcpBinding>
78 
79     </bindings>
80 
81   </system.serviceModel>

 

(3)       在windows服務啟動的時候啟動WCF服務

 1 using SelfHelper;
 2 
 3 using System;
 4 
 5 using System.Collections.Generic;
 6 
 7 using System.ComponentModel;
 8 
 9 using System.Data;
10 
11 using System.Diagnostics;
12 
13 using System.Linq;
14 
15 using System.ServiceProcess;
16 
17 using System.Text;
18 
19 using System.ServiceModel;
20 
21  
22 
23 namespace SelfSQL
24 
25 {
26 
27     public partial class SelfSQLServer : ServiceBase
28 
29     {
30 
31         public SelfSQLServer()
32 
33         {
34 
35             InitializeComponent();
36 
37         }
38 
39  
40 
41         ServiceHost host = new ServiceHost(typeof(SelfWcfService.SelfSQLData));
42 
43         protected override void OnStart(string[] args)
44 
45         {
46 
47             LogWriter.WriteLog("服務已啟動!");
48 
49             try
50 
51             {
52 
53                 host.Open();
54 
55                 LogWriter.WriteLog("WCF啟動成功");
56 
57             }
58 
59             catch (Exception ex)
60 
61             {
62 
63                 LogWriter.WriteLog("WCF啟動異常:" + ex.ToString());
64 
65             }
66 
67            
68 
69         }
70 
71  
72 
73         protected override void OnStop()
74 
75         {
76 
77             LogWriter.WriteLog("服務已停止!");
78 
79         }
80 
81     }
82 
83 }

 

(4)       啟動windows服務進行測試

 

 

 

第3步:創建客戶端進行測試

首先在控制台程序中添加服務引用

 

 

然后就可以調用客戶端對象進行測試了。

測試代碼:

  1 using System;
  2 
  3 using System.Collections.Generic;
  4 
  5 using System.Data;
  6 
  7 using System.Linq;
  8 
  9 using System.Text;
 10 
 11  
 12 
 13 namespace SelfSQLClient
 14 
 15 {
 16 
 17     class Program
 18 
 19     {
 20 
 21         static void Main(string[] args)
 22 
 23         {
 24 
 25             SelfSQLServiceCilent.SelfSQLDataClient client = new SelfSQLServiceCilent.SelfSQLDataClient();
 26 
 27             DataTable dt1 = new DataTable();           
 28 
 29  
 30 
 31             DataColumn idColumn = new DataColumn();
 32 
 33             idColumn.DataType = System.Type.GetType("System.Int32");
 34 
 35             idColumn.ColumnName = "t1";
 36 
 37             idColumn.AutoIncrement = true;
 38 
 39             dt1.Columns.Add(idColumn);
 40 
 41  
 42 
 43             DataColumn aColumn = new DataColumn();
 44 
 45             aColumn.DataType = System.Type.GetType("System.Int32");
 46 
 47             aColumn.ColumnName = "t2";
 48 
 49             aColumn.AutoIncrement = false;
 50 
 51             dt1.Columns.Add(aColumn);
 52 
 53  
 54 
 55             DataColumn bColumn = new DataColumn();
 56 
 57             bColumn.DataType = System.Type.GetType("System.DateTime");
 58 
 59             bColumn.ColumnName = "t3";
 60 
 61             bColumn.AutoIncrement = false;
 62 
 63             dt1.Columns.Add(bColumn);
 64 
 65  
 66 
 67             for (int i = 0; i < 3; i++)
 68 
 69             {
 70 
 71                 DataRow dr = dt1.NewRow();
 72 
 73                 dr[0] = i;
 74 
 75                 dr[1] = i + 1;
 76 
 77                 dr[2] = DateTime.Now;
 78 
 79                 dt1.Rows.Add(dr);
 80 
 81             }
 82 
 83             dt1.TableName = "FirstTable";
 84 
 85             client.CreateTable("FirstTable", dt1);
 86 
 87  
 88 
 89             Dictionary<string, DataTable> dts = client.GetData();
 90 
 91             foreach (var dt in dts)
 92 
 93             {
 94 
 95                 Console.WriteLine("表名:" + dt.Key);
 96 
 97                 string colNames = string.Empty;
 98 
 99                 foreach (var col in dt.Value.Columns)
100 
101                 {
102 
103                     colNames += col.ToString() + "--";
104 
105                 }
106 
107                 Console.WriteLine("字段:" + colNames);               
108 
109                 foreach (DataRow val in dt.Value.Rows)
110 
111                 {
112 
113                     string vals = string.Empty;
114 
115                     for (int i = 0; i < dt.Value.Columns.Count; i++)
116 
117                     {
118 
119                         vals += val[i] + "--";
120 
121                     }
122 
123                     Console.WriteLine("數據:" + vals);
124 
125                 }
126 
127             }
128 
129         }
130 
131     }
132 
133 }

 

輸出結果:

 

添加SecondTable表:

輸出結果:

 

 

 

總結:

到這里相信大家都知道了,所謂的“緩存數據庫”不過是個數據結構為Dictionary<string,DataTable>的靜態變量而已,有人可能要問,直接定義在應用程序中不就完事了嗎?還有必要又是創建WCF服務,又是創建Windows服務的嗎?當然,在這里像玩具一般的“緩存數據庫”確實沒必要這么大費周章,它並不友好,要新增數據需要大量初始化DataTable對象的代碼,它也承載不了太大的數據量,畢竟內存依舊在CLR托管堆中,它的穩定性與安全性更是無從談起,因為毫無並發量較高的邏輯處理,但是,我做這件事情的初衷,並不是要寫一個可以匹敵類似於redis一樣的數據庫,而是如前言所說,正因為這個“玩具”它存在這么多的缺陷,那么對這些缺陷進行一定程度完善的過程,也是加深對多線程、設計模式、非關系型數據庫等方面學習的一個過程。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM