天天看点

Qt数据库之数据库连接池

前面的章节里,我们使用了下面的函数创建和取得数据库连接:

需要维护连接的名字

获取连接的时候需要传入连接的名字

获取连接的时候不知道连接是否已经被使用,使用多线程的时候,每个线程都必须使用不同的连接

控制连接的最大数量比较困难,因为不能在程序里无限制的创建连接

连接断了后不会自动重连

删除连接不方便

这一节我们将创建一个简易的数据库连接池,就是为了解决上面的几个问题。使用数据库连接池后,只需要关心下面 3 个函数,而且刚刚提到的那些弊端都通过连接池解决了,对调用者是透明的。

<col>

功能

代码

获取连接

QSqlDatabase db = ConnectionPool::openConnection()

释放连接

ConnectionPool::closeConnection(db)

关闭连接池

ConnectionPool::release() // 一般在 main() 函数返回前调用

在具体介绍数据库连接池的实现之前,先来看看怎么使用。

获取连接时不需要了解连接的名字

支持多线程,保证获取到的连接一定是没有被其他线程正在使用

按需创建连接

可以创建多个连接

可以控制连接的数量

连接被复用,不是每次都重新创建一个新的连接

连接断开了后会自动重连

当无可用连接时,获取连接的线程会等待一定时间尝试继续获取,直到超时才会返回一个无效的连接

关闭连接很简单

数据库连接池的实现只需要 2 个文件:​<code>​ConnectionPool.h​</code>​ 和 ​<code>​ConnectionPool.cpp​</code>​。下面会列出文件的内容加以介绍。

​<code>​ConnectionPool.h​</code>​

​<code>​openConnection()​</code>​ 用于从连接池里获取连接。

​<code>​closeConnection(QSqlDatabase connection)​</code>​ 并不会真正的关闭连接,而是把连接放回连接池复用。连接的底层是通过 Socket 来通讯的,建立 Socket 连接是非常耗时的,如果每个连接都在使用完后就给断开 Socket 连接,需要的时候再重新建立 Socket连接是非常浪费的,所以要尽量的复用以提高效率。

​<code>​release()​</code>​ 真正的关闭所有的连接,一般在程序结束的时候才调用,在 main() 函数的 return 语句前。

​<code>​usedConnectionNames​</code>​ 保存正在被使用的连接的名字,用于保证同一个连接不会同时被多个线程使用。

​<code>​unusedConnectionNames​</code>​ 保存没有被使用的连接的名字,它们对应的连接在调用 ​<code>​openConnection()​</code>​ 时返回。

如果 ​<code>​testOnBorrow​</code>​ 为 true,则连接断开后会自动重新连接(例如数据库程序崩溃了,网络的原因等导致连接断开了)。但是每次获取连接的时候都会先查询一下数据库,如果发现连接无效则重新建立连接。​<code>​testOnBorrow​</code>​ 为 true 时,需要提供一条 SQL 语句用于测试查询,例如 MySQL 下可以用 ​<code>​SELECT 1​</code>​。如果 ​<code>​testOnBorrow​</code>​ 为 false,则连接断开后不会自动重新连接。需要注意的是,Qt 里已经建立好的数据库连接当连接断开后调用 QSqlDatabase::isOpen() 返回的值仍然是 true,因为先前的时候已经建立好了连接,Qt 里没有提供判断底层连接断开的方法或者信号,所以 QSqlDatabase::isOpen() 返回的仍然是先前的状态 true。

​<code>​testOnBorrowSql​</code>​ 为测试访问数据库的 SQL,一般是一个非常轻量级的 SQL,如 ​<code>​SELECT 1​</code>​。

获取连接的时候,如果没有可用连接,我们的策略并不是直接返回一个无效的连接,而是等待 ​<code>​waitInterval​</code>​ 毫秒,如果期间有连接被释放回连接池里就返回这个连接,没有就继续等待 ​<code>​waitInterval​</code>​ 毫秒,再看看有没有可用连接,直到等待 ​<code>​maxWaitTime​</code>​ 毫秒仍然没有可用连接才返回一个无效的连接。

因为我们不能在程序里无限制的创建连接,用 ​<code>​maxConnectionCount​</code>​ 来控制创建连接的最大数量。

​<code>​ConnectionPool.cpp​</code>​