zoukankan      html  css  js  c++  java
  • 自定义个“缓存数据库”玩玩

    前言:首先声明,此文题目算是标题党的一种,是本人为了完成与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一样的数据库,而是如前言所说,正因为这个“玩具”它存在这么多的缺陷,那么对这些缺陷进行一定程度完善的过程,也是加深对多线程、设计模式、非关系型数据库等方面学习的一个过程。

  • 相关阅读:
    1012 最大公约数和最小公倍数问题 2001年NOIP全国联赛普及组
    数论笔记
    Codevs 1200 同余方程 2012年NOIP全国联赛提高组
    Codevs 1213 解的个数(exgcd)
    Qbxt 模拟赛&&day-8
    NOIP 模拟赛 那些年,我们学过的文化课 --致已退役的fqk神犇.
    OI路上 day -9
    P3178 [HAOI2015]树上操作
    P3979 遥远的国度
    P4092 [HEOI2016/TJOI2016]树
  • 原文地址:https://www.cnblogs.com/BradPitt/p/8203731.html
Copyright © 2011-2022 走看看