[聚合文章] 自定义个“缓存数据库”玩玩

.Net 2018-01-05 17 阅读

前言:首先声明,此文题目算是标题党的一种,是本人为了完成与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 SelfWcfService20 21 {22 23     // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IService1”。24 25     [ServiceContract]26 27     public interface ISelfSQLData28 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 SQLData66 67     {68 69         [DataMember]70 71         public Dictionary<string, DataTable> DataTables { get; set; }       72 73     }74 75    76 77     [DataContract]78 79     public class SelfDataRow80 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                 try124 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             else144 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                 try182 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             else202 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                 try240 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             else260 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                 try290 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             else310 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 SelfSQL24 25 {26 27     public partial class SelfSQLServer : ServiceBase28 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             try50 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一样的数据库,而是如前言所说,正因为这个“玩具”它存在这么多的缺陷,那么对这些缺陷进行一定程度完善的过程,也是加深对多线程、设计模式、非关系型数据库等方面学习的一个过程。

 

注:本文内容来自互联网,旨在为开发者提供分享、交流的平台。如有涉及文章版权等事宜,请你联系站长进行处理。