记得以前在公司上班时,有时候白天的活没干完,我就会把工作带回家晚上加班继续做。但是,我们开发用的数据库是部署在公司局网内部的一台服务器上的,在家里是肯定连不上这台机器的。在家里没有数据库,服务端就跑不起来,功能也就没办法调试。后来我们的解决方法就是使用虚拟数据库。在公司上班时,就使用公司局网的真实数据库;回到家,就使用内存中虚拟的数据库,做一些基本的功能调试,绝对是足够了。

GG之前的版本一直只支持虚拟数据库,因为部署、演示都非常方便。后来有很多朋友要求增加对真实数据库的支持,那么这次GG的最新版本V4.4 就满足了大家的这一需求,真实数据库使用SqlServer(2000/2005/2008),并使用一个配置就可以在真实/虚拟数据库之间自由切换。本文就将详细介绍我们是如何实现在虚拟数据库和真实数据库之间自由切换这一功能的。

想要直接下载体验的朋友请点击:“下载中心”

一. 什么是虚拟数据库?

刚baidu了一下,似乎没有“虚拟数据库”这个专业术语。那么我就结合类似上面的使用场景,按照自己的理解来简单解释一下,虚拟数据库有以下几个要点:

(1)“虚拟”是和“真实”相对的。它不是一个真实的数据库,而是一个数据库的模拟。

(2)只在软件运行的过程中存在。比如,当服务端启动时,会在内存中构建这个虚拟数据库。

(3)只存在于内存中,没有持久化机制。比如,在服务端运行过程中,会对虚拟数据库进行CRUD操作,但是当服务端重启后,这些修改就都会丢失,虚拟数据库又会恢复到它的初始状态。

(4)不需要任何部署。这是虚拟数据库最方便的地方和最大的好处了。我们都知道有时仅仅为了给客户演示一个简单的小功能,就需要安装一个庞大的SqlServer或Oralce,是多么痛苦的一件事!

二. 虚拟数据库如何实现?

我们经常用Dictionary<,>模拟一个虚拟数据库中的表,Dictionary的key就模拟表的主键,value就模拟一条记录。比如,GG中的用户表GGUser,在虚拟数据库中就可以这样模拟:

    //模拟GGUser表
private Dictionary<string, GGUser> userTable = new Dictionary<string, GGUser>(); //模拟插入一个GGUser
public void InsertUser(GGUser user)
{
lock (this.userTable)
{
this.userTable.Add(user.ID, user);
}
}

类似上面的代码,我们可以很快地写出与GGUser表相关的CRUD操作。同理,也可以模拟GGGroup(GG群)表、ChatMessageRecord(聊天记录)表等等。

我们把所有对虚拟表的操作全封装在一个类VirtualDB中,于是,我们就可以程VirtualDB就是虚拟数据库的抽象了。

在VirtualDB的构造函数中,我们可以为虚拟表添加一些测试数据,这样,服务端启动后,就有一些基础数据提供给调试、测试、或Demo演示使用了。

三. 如何实现在虚拟数据库和真实数据库之间切换?

1. 里氏替换原则

    我们首先回忆一下,经典OO设计原则中的一个:里氏替换原则。这个原则是这样说的:所有引用基类的地方必须能够透明地使用其子类的对象。

似乎有点拗口,下面就结合GG中的实现解释一下:

(1)GG中用于表示虚拟数据库的类是VirtualDB类,用于表示真实数据库的类是RealDB类。

(2)VirtualDB类和RealDB类都从接口IDBPersister接口继承。

(3)但是,GG服务端程序中凡是涉及到数据库访问操作的地方,既不使用VirtualDB、也不使用RealDB,而是使用IDBPersister。

这样,我们就只需要在程序启动的时候,指定将VirtualDB实例或RealDB实例指派给IDBPersister引用,就可以让整个服务端统一地访问虚拟数据库或是真实数据库了。

结合这个实例,我们把里氏替换原则放到这个场景中,其意思就是:在程序中不要依赖具体的实现类(VirtualDB和RealDB),而是依赖于它们的共同接口(IDBPersister)。这样,替换就很方便了。

2. 使用配置文件

如果打算将使用VirtualDB还是使用RealDB的决定权交给用户,那么只需要在配置文件中增加一个配置项即可。比如:

    <!--使用内存虚拟数据库-->
<add key="UseVirtualDB" value="false"/>
<!--数据库名称-->
<add key="DBName" value="GG2014"/>
<!--数据库IP-->
<add key="DBIP" value="127.0.0.1"/>
<!--数据库sa的密码-->
<add key="SaPwd" value="123qwe"/>

上述的配置,还包含了数据库的相关信息。如果要使用虚拟的数据库,只需要将UseVirtualDB项配置为true即可。

在服务端启动的时候,读取配置,然后决定是否使用虚拟数据库。

    IDBPersister persister;
if (bool.Parse(ConfigurationManager.AppSettings["UseVirtualDB"]))
{
persister = new VirtualDB();
}
else
{
persister = new RealDB( ConfigurationManager.AppSettings["DBName"] ,ConfigurationManager.AppSettings["DBIP"], ConfigurationManager.AppSettings["SaPwd"]);
} GlobalCache globalCache = new GlobalCache(persister);

四.GG V4.4 源码

  下载最新版本,请转到这里。 

GG是可在广域网部署运行的QQ高仿版,2013.8.7发布V1.0版本,至今最新是4.4版本,关于GG更详细的介绍,可以查看 可在广域网部署运行的QQ高仿版 -- GG2014总览

  在GG的最新版本中使用了上述方案以支持在真实数据库和虚拟数据库之间相互切换。

________________________________________________________________________

欢迎和我探讨关于 GG 和 GGMeeting 的一切,我的QQ:2027224508,多多交流!

大家有什么问题和建议,可以留言,也可以发送email到我邮箱:2027224508@qq.com。

如果你觉得还不错,请粉我,顺便再顶一下啊

如何做到在虚拟数据库和真实数据库之间自由切换?【低调赠送:QQ高仿版GG 4.4 最新源码】的更多相关文章

  1. PHP批量替换MySql数据库中的数据内容(替换MySql数据库内容源码)

    PHP批量替换MySql数据库内容 UTF-8 1.0版 <?php //声明 //1.本源码开发意图:作者在使用一些CMS建站的时候发现很多CMS把网址写入到数据库了,如果换网址,那么就需要更 ...

  2. Sql Server数据库备份脚本以及如何在阿里云云数据库RDS还原数据库(代码源自阿里云)

    今天研究阿里云服务数据库的迁移,备份和还原的时候,在阿里云web后台发现了一个很好用的sql脚本,就默默地偷了过来,它可以支持全量备份,差异备份和日志备份,代码解释也都很清楚,我也尝试着跑了一下,性能 ...

  3. 虚拟dom和真实dom的转化和class解析的顺序

    昨天出去溜了一圈,被问到几个问题回来整理了一下,当被特意问到一看感觉就会的问题,千万要不要急于回答,先想想,因为这往往是一个被忽略的坑(例如class解析顺序)!!! 1.写出虚拟dom和真实dom之 ...

  4. 1.NetDh框架之数据库操作层--Dapper简单封装,可支持多库实例、多种数据库类型等(附源码和示例代码)

    1.NetDh框架开始的需求场景 需求场景: 1.之前公司有不同.net项目组,有的项目是用SqlServer做数据库,有的项目是用Oracle,后面也有可能会用到Mysql等,而且要考虑后续扩展成主 ...

  5. Godaddy虚拟主机新建mysql数据库 2019最新

    第一次用狗爹,完全摸不着路子. 网站本地已搭建,不知道数据库是在哪里上传. 百度搜索结果都是四五年前的旧内容,耽误时间. 还是问客服,Godaddy的客服确实不赖 godaddy虚拟主机如何新建数据库 ...

  6. MySQL之 视图,触发器,存储过程,函数,事物,数据库锁,数据库备份

    1.视图 视图: 是一个虚拟表,其内容由查询定义: 视图有如下特点;  1. 视图的列可以来自不同的表,是表的抽象和逻辑意义上建立的新关系.  2. 视图是由基本表(实表)产生的表(虚表).  3. ...

  7. 数据库MySQL之 视图、触发器、存储过程、函数、事务、数据库锁、数据库备份、事件

    数据库MySQL之 视图.触发器.存储过程.函数.事务.数据库锁.数据库备份.事件 浏览目录 视图 触发器 存储过程 函数 事务 数据库锁 数据库备份 事件 一.视图 1.视图概念 视图是一个虚拟表, ...

  8. MYSQL之视图、触发器、存储过程、函数、事物、数据库锁和数据库备份

    一.视图 -- view 视图:是一个虚报表,其内容由查询定义.同真实的表一样,视图包含一系列带有名称的列和行数据. 视图有如下特点: 1.视图的列可以来自不同的表,是表的抽象和逻辑意义上建立的新关系 ...

  9. C# DateTime的11种构造函数 [Abp 源码分析]十五、自动审计记录 .Net 登陆的时候添加验证码 使用Topshelf开发Windows服务、记录日志 日常杂记——C#验证码 c#_生成图片式验证码 C# 利用SharpZipLib生成压缩包 Sql2012如何将远程服务器数据库及表、表结构、表数据导入本地数据库

    C# DateTime的11种构造函数   别的也不多说没直接贴代码 using System; using System.Collections.Generic; using System.Glob ...

随机推荐

  1. 关于MVC中View使用自定义方法

    今天学习到了在MVC的View中使用自定义方法,很简单,下面分享一下. 1.首先在项目下面建立一个文件夹,用于存我们写的自定义方法. 2.在新建文件夹中新增一个类,命名随便取(最好还是和自定义方法关联 ...

  2. httpServletRequest对象、filter、servlet、servlet容器、catalina、tomcat、以及web容器之间的关系

    学习servlet的时候经常感到疑惑 HttpServletRequest是服务器创建的?还是servlet容器创建的? 过滤器是服务器创建的?还是servlet容器创建的? serlet容器和tom ...

  3. Ceph剖析:Leader选举

    作者:吴香伟 发表于 2014/09/11 版权声明:可以任意转载,转载时务必以超链接形式标明文章原始出处和作者信息以及版权声明 Paxos算法存在活锁问题.从节点中选出Leader,然后将所有对数据 ...

  4. myeclipse,eclipse打开当前文件所在文件夹

    方法一: eclipse打开当前文件所在文件夹的插件Run-->External Tools-->External Tools Configurations...new 一个 progra ...

  5. AngularJS的小知识点

    小知识点:$scope和$rootScope (1)每次使用ngController指令,都会调用控制器的创建函数,创建出一个控制器对象. (2)每次创建一个控制器对象,AngularJS都会创建一个 ...

  6. C# "=="、Equals()、ReferenceEquals()区别

    对于值类型: ; ; 1.== 比较的是值内容 2.age2.Equals(age1) = false; Equals比较前需要转换成同类型,age1(int型)需显示转换成byte型 3.age1. ...

  7. C#中语音合成简单使用

    我使用的是vs2013 1.在项目中添加引用,项目->添加引用->COM选择Microsoft Speech Object Library 2.在需要使用语音合成的地方调用代码: SpVo ...

  8. RabbitMQ 问题记录

    1. rabbitmq安装后无法运行,报错“unable to connect to node rabbit@XXXX: nodedown”. 怀疑局域网内有相同名称的计算机安装了rabbitmq,造 ...

  9. 用sql语句清除日志

    DUMP TRANSACTION [数据库] WITH NO_LOGBACKUP LOG [数据库] WITH NO_LOGDBCC SHRINKDATABASE([数据库])

  10. 【dubbo】dubbo控制台搭建

    1.gitHub上下载dubbo 2.cmd下运行 cd ~/dubbomvn clean install -Dmaven.test.skip 3.cd ~/dubbo/dubbo-admin mvn ...