﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-gogoplayer-随笔分类-MySQL &amp;&amp; MySQL++</title><link>http://www.cppblog.com/gogoplayer/category/4745.html</link><description>Ogre,MySQL&amp;&amp;MySQL++,光线跟踪</description><language>zh-cn</language><lastBuildDate>Tue, 20 May 2008 00:32:56 GMT</lastBuildDate><pubDate>Tue, 20 May 2008 00:32:56 GMT</pubDate><ttl>60</ttl><item><title>数据库服务器和MySQL++</title><link>http://www.cppblog.com/gogoplayer/archive/2007/07/18/28317.html</link><dc:creator>gogoplayer</dc:creator><author>gogoplayer</author><pubDate>Wed, 18 Jul 2007 15:12:00 GMT</pubDate><guid>http://www.cppblog.com/gogoplayer/archive/2007/07/18/28317.html</guid><wfw:comment>http://www.cppblog.com/gogoplayer/comments/28317.html</wfw:comment><comments>http://www.cppblog.com/gogoplayer/archive/2007/07/18/28317.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/gogoplayer/comments/commentRss/28317.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/gogoplayer/services/trackbacks/28317.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp;这个月接到数据库服务器设计任务，网络部分的IOCP已经封装完成，剩下的是数据库设计部分，原先数据库部分API采用的是MySQL C的，C的代码虽然也简单，但是会有些混乱，没有MySQL++封装后好用，昨天看MySQL C的代码的时候感觉C已经比较好用了，但是这一切在我使用了MySQL++后彻底改变了，MySQL++基于MySQL之上，对C的API进行了再一次的封装，通过这次封装，屏蔽了原先C代码的很多细节，而且加上了异常机制，例如数据库连接、事务、结果集等对象概念突出了，还有他的SSQLS功能，太好用了，它就像SQL模板，用来生成各种SQL语句。<br>&nbsp;&nbsp;&nbsp;由于是数据库服务器设计，必然涉及到多线程操作，而且不仅是应用程序的多线程，数据库操作也要支持多线程，设想如果一个数据库操作导致阻塞导致，那么面对游戏的数据库服务器，将是海量的数据库操作，这样的延时那可就不得了了。先来说说应用程序的多线程操作，是这样的，目前的设计是多个登陆服务器链接一个数据库服务器，通过登陆服务器来提交数据库操作请求，一个登陆服务器可以有很多玩家连在那里，玩家通过帐号id来唯一标识，这样一说脉络就清晰了。玩家通过登陆服务器（其实玩家最初还要进过网关服务器中转，这里掠过）提交不同的数据库操作，数据库服务器接受到数据库操作消息就把这个消息放到对应的线程去操作，这个线程也不是随机找一个空闲线程操作就可以的，因为涉及到网络同步的复杂问题，我们必须保证同一个玩家提出多个的数据库操作依次执行，也就是队列，不能出现玩家的第二个数据库操作完成，而第一个却还没动，原因应很简单，玩家的操作是有前后连续性的，顺序错误有时候会带来灾难性的后果，要知道数据库可是存放着玩家的资料，诸如玩家等级，装备，攻防参数等重要信息，如果这些数据出错，我想你应该知道这个利害了吧。<br>&nbsp;&nbsp;&nbsp;废话少说，先来看下数据库多线程简单图示：<br><img height=256 alt="" src="http://www.cppblog.com/images/cppblog_com/gogoplayer/DBServerPic1.JPG" width=512 border=0><br>&nbsp;&nbsp;&nbsp;上图是应用程序多线程示例，每个线程有个数据库操作队列，不同玩家的数据库操作会通过帐号id被放到相应的线程中，至于这其中的同步互斥，无非就是用用互斥量，临界区控制一下，没什么难度。每个线程采用事件机制激活，当有来自网络的数据被解析为一个数据库操作并被投递到一个数据库操作队列（DBOperationQueue）后，激活事件，线程原先是在等待事件，现在被激活了，自然就运行了，开始解析操作，每个线程内部会创建一个数据库连接，对应于MySQL++，就是一个mysqlpp::Connection，其实在mysqlpp::Connection的内部，会自动调用mysql_thread_init()这个MySQL的C API，这样原本我以为c++的封装和C就对等了，但是搜索MySQL++源代码发现他并没有调用mysql_thread_end()，这就有问题了，没有调用这个函数将不会析构一些数据库线程内的数据，造成内存泄漏，带着这个疑问再找下去，发现了mysqlpp::Connection自带lock机制，也就是同一个线程对他的操作将会被自动互斥，没有调用mysql_thread_end()，只是mysqlpp::Connection没有使用MySQL线程相关的那部分代码，自己实现了lock机制，实际上是一回事。</p>
<p>&nbsp;&nbsp;&nbsp;上面的图示显示的全是数据库操作线程，实际上还有一个网络消息处理线程，这个线程有IOCP管理，因为DBServer继承自IOCP，大致的流程就是这样，网络消息处理线程解析消息，并把数据库操作放到相应的数据库操作队列，每个数据库操作线程只处理对应的队列，数据库线程可以开多个，我们的工作中开了10几个，至此，只要妥善处理好他们的同步互斥关系，数据库服务器就会稳定的的运行，虽说同步互斥不难，但是数据库服务器的设计充斥着大量的同步互斥操作，稍不注意，有可能就调入死锁、数据异常陷阱中，多多留心啊，^_^。</p>
<img src ="http://www.cppblog.com/gogoplayer/aggbug/28317.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/gogoplayer/" target="_blank">gogoplayer</a> 2007-07-18 23:12 <a href="http://www.cppblog.com/gogoplayer/archive/2007/07/18/28317.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>