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

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。

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

最新文章

  1. 解决vs创建或打开C++浏览数据库文件*.sdf时发生错误的问题
  2. Mono 3.0.12 支持可移植类库
  3. HTML label标签的for属性--input标签的accesskey属性
  4. mysql远程连接命令(转)
  5. 9.S5PV210的时钟系统
  6. HDU 3374 String Problem (KMP+最大最小表示)
  7. bootstrap学习笔记&lt;八&gt;(bootstrap核心布局风格——栅格系统)
  8. python2.+进化至python3.+ 语法变动差异(不定期更新)
  9. fedora20 播放aiv视频
  10. KEIL C51的XBYTE关键字
  11. python 的日志相关应用
  12. 《深入理解Java虚拟机》学习笔记之字节码执行引擎
  13. AddDigitsTotal - 把数字中单个数相加
  14. json与xml的比较
  15. C语言的学习
  16. Android 开发 图片网络缓存加载框架Fresco
  17. IDEA 启动项目前的配置--或过程遇到的问题
  18. cv::ACCESS_MASK指定不明确的错误
  19. this与$scope
  20. laravel5.5源码笔记(五、Pipeline管道模式)

热门文章

  1. c++ 覆盖、重载与隐藏
  2. 强连通分量的一二三 | | JZOJ【P1232】 | | 我也不知道我写的什么
  3. flask-admin章节三:数据库迁移工具 alembic初步使用
  4. net软件自动生成开发编程框架编程机器人
  5. c# htmtToPDF
  6. Selenium2+python 常用函数汇总
  7. seaJS 简单例子,理解seaJS
  8. Numpy 中一维数据转置的几种方法
  9. new出对象的作用
  10. &lt;&lt;UML大战需求分析&gt;&gt;阅读笔记(2)