一般可用下面的函数创建和取得数据库连接:
void createConnectionByName(const QString &connectionName)
{
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL", connectionName);
db.setHostName("127.0.0.1");
db.setDatabaseName("qt"); // 如果是 SQLite 则为数据库文件名
db.setUserName("root"); // 如果是 SQLite 不需要
db.setPassword("root"); // 如果是 SQLite 不需要
if(!db.open())
{
qDebug() << "Connect to MySql error: " << db.lastError().text();
return;
}
}
QSqlDatabase getConnectionByName(const QString &connectionName)
{
return QSqlDatabase::database(connectionName);
}
虽然抽象出了连接的创建和获取,但是有几个弊端:
- 需要维护连接的名字
- 获取连接的时候需要传入连接的名字
- 获取连接的时候不知道连接是否已经被使用,使用多线程的时候,每个线程都必须使用不同的连接
- 控制连接的最大数量比较困难,因为不能在程序里无限制的创建连接
- 连接断了后不会自动重连
- 删除连接不方便
这一节我们将创建一个简易的数据库连接池,就是为了解决上面的几个问题。使用数据库连接池后,只需要关心下面 3 个函数,而且刚刚提到的那些弊端都通过连接池解决了,对调用者是透明的。
功能 | 代码 |
---|---|
获取连接 | QSqlDatabase db = ConnectionPool::openConnection() |
释放连接 | ConnectionPool::closeConnection(db) |
关闭连接池 | ConnectionPool::release() // 一般在 main() 函数返回前调用 |
数据库连接池的使用
在具体介绍数据库连接池的实现之前,先来看看怎么使用。
#include "ConnectionPool.h"
#include <QDebug>
void foo()
{
// 1. 从数据库连接池里取得连接
QSqlDatabase db = ConnectionPool::openConnection();
// 2. 使用连接查询数据库
QSqlQuery query(db);
query.exec("SELECT * FROM user where id=1");
while(query.next())
{
qDebug() << query.value("username").toString();
}
// 3. 连接使用完后需要释放回数据库连接池
ConnectionPool::closeConnection(db);
}
int main(int argc, char *argv[])
{
foo();
ConnectionPool::release(); // 4. 释放数据库连接
return 0;
}
数据库连接池的特点
- 获取连接时不需要了解连接的名字
- 支持多线程,保证获取到的连接一定是没有被其他线程正在使用
- 按需创建连接
- 可以创建多个连接
- 可以控制连接的数量
- 连接被复用,不是每次都重新创建一个新的连接
- 连接断开了后会自动重连
- 当无可用连接时,获取连接的线程会等待一定时间尝试继续获取,直到超时才会返回一个无效的连接
- 关闭连接很简单
数据库连接池的实现
数据库连接池的实现只需要 2 个文件:ConnectionPool.h
和 ConnectionPool.cpp
。下面会列出文件的内容加以介绍
ConnectionPool.h
#ifndef CONNECTIONPOOL_H
#define CONNECTIONPOOL_H
#include <QtSql>
#include <QQueue>
#include <QString>
#include <QMutex>
#include <QMutexLocker>
class ConnectionPool
{
public:
static void release(); // 关闭所有的数据库连接
static QSqlDatabase openConnection(); // 获取数据库连接
static void closeConnection(QSqlDatabase connection); // 释放数据库连接回连接池
~ConnectionPool();
private:
static ConnectionPool& getInstance();
ConnectionPool();
ConnectionPool(const ConnectionPool &other);
ConnectionPool& operator=(const Connec