一种基于Qt的可伸缩的全异步C/S架构服务器实现(四)数据库的多线程操作

四、数据库的多线程操作

在多线程服务中,数据库是必不可少的组成部分。Qt通过 QtSql模块支持数据库的通用访问。通过插件,可支持目前主流的数据库系统。Qt的数据库操作注意事项在我前面的博文中已经有了涉及,这里简要重复一遍。

1、线程内注册与连接数据库的竞争问题

        Qt文档上对多线程下数据库应用的注意事项写的很简明,一个线程创建的 QSqlDatabase 对象和 查出来的 QSqlQuery 对象只能给本线程用(注意,是对象,不是数据库连接本身,连接本身用名字可以多线程使用),其他情况是“不支持的”。在一个需要有几个线程并发访问不同数据库的应用中,试图在各个线程的起始分别以不同的名称调用  addDatabase / database 、open,程序偶然会崩溃,跟踪后发现,虽然Qt 声称很多方法是“线程安全”的,但是几个方法串起来,就出问题了。Qt 会动态的加载数据库的plugin, 加载 plug in 的部分,涉及到对本地库文件的管理,这一部分,出现了竞争。在初始连接部分设置 Mutex 保护,从 addDatabase / database到 open 的部分,要保证其原子性。


2、数据库连接意外断裂后,恢复连接的问题

      在MFC 中,一旦中途TCP连接断裂,直接重新 Open 就可以了。在Qt 里,这一招不好使了。即便 调用了 close ,再次open 也是不行的。处理方法:

      在检测到问题出现后,关闭连接,并 removeDatabase;   而后,不要立刻 addDatabase, 反而是要回到该连接所在的事件循环。没有详细跟源码,很可能在 removeDatabase 后的事件循环中,Qt 内部做了一些释放操作。  实际应用中,直接显式调用processEvent() 方法强制循环。  在多线程下,注意1中的问题,需要 Mutex保护。


3、数据库插件的依赖性问题

      在 Windows 下,有时我们的机器上按了好几个 Qt 版本,依赖开发环境的继承环境适应不同的版本。这有两个问题。一是发布程序的时候,数据库驱动依赖的dll 也要与可执行文件在同一路径下发布。比如 mysql 的 dll, PostgreSQL 的依赖等。二是在集成开发环境中,这些依赖也要位于执行档文件夹下。否则,会造成虽然可以枚举到可用驱动,但是连接不上。调试一下就知道,原来是在路径中找不到依赖项,导致dll加载失败!


     Qt的数据库操作自成一派,相对于复杂的 ADO \ODBC\DAO\OLEDB 等传统 C++ 访问数据库的方法,还是很先进的,充分体现了 OO 的理念。设计者把进程内的数据库连接作为一种资源,每个连接有一个唯一的名字,可以通过全局的 addDatabase, removeDatabase, cloneDatabase 来增删,想用的时候,直接用全局的 database 来获取。这样的好处,是大大节省了开发者的负担。以前为了传递一个数据库连接的变量,必须在很多方法入库处添加指向这个变量的指针或者引用,有时候不得不在对象的属性中加入静态的变量,来记录这个连接。现在,什么时候想用,给个名字就可以了,不需要传递。当然,文档说的是比较简化的,至少有两点要注意,

     1)这些增删方法号称是线程安全的,但是,在实际应用中,还是要注意用 Mutex 保护全局创建流程,或者,重载这些函数,创建自己的安全版本。

     2)一个线程创建的数据库对象(如 addDatabase 的返回值)只能在同一线程使用,但是,addDatabase 注册的连接(名字是开发者定)可以跨线程使用,唯一需要注意的是,在调用全局方法的时候,要有原子保护。


你可能感兴趣的:(多线程,C++,数据库,qt,cs)