Qt中的数据库连接池
Posted
技术标签:
【中文标题】Qt中的数据库连接池【英文标题】:DB connection pool in Qt 【发布时间】:2017-11-16 05:34:23 【问题描述】:我有一个 Qt 应用程序,它有一个 DatabaseService
单例,只有一个 QSqlDatabase
实例,许多线程应该使用这个 QSqlDatabase
实例,当某些线程使用 QSqlDatabase
实例时,互斥锁被锁定。但我知道这不是这项任务的最佳模式。
我应该在这里使用某种数据库连接池还是类似的东西?以及如何在 Qt 中实现它?
请提供一些例子。
UPD:
其实例已经拥有自己的线程的类,该类将有多个实例:
.cpp:
//...
QFuture<QMap<QString, QString>> future = QtConcurrent::run(DatabaseService::executeQuery, sqlCommand);
future.waitForFinished();
//...
数据库服务:
.h:
class DatabaseService
public:
//...
static QMap<QString, QString> executeQuery(QString command);
private:
static QThreadStorage<QSqlDatabase> mDatabasePool;
static QSqlDatabase getDatabase();
;
.cpp:
//...
QThreadStorage<QSqlDatabase> DatabaseService::mDatabasePool;
QSqlDatabase DatabaseService::getDatabase()
if(DatabaseService::mDatabasePool.hasLocalData())
return DatabaseService::mDatabasePool.localData();
else
auto database = QSqlDatabase::addDatabase("QPSQL", QUuid::createUuid().toString());
database.setHostName("hostName");
database.setDatabaseName("databaseName");
database.setUserName("user");
database.setPassword("password");
DatabaseService::mDatabasePool.setLocalData(database);
return database;
QMap<QString,QString> DatabaseService::executeQuery(QString command)
QSqlQuery query (DatabaseService::getDatabase());
query.exec(command);
//...
return result;
//...
UPD 2:
main.cpp:
int main(int argc, char *argv[])
QCoreApplication a(argc, argv);
MyServer server;
server.listen(QHostAddress::Any, 1234);
return a.exec();
我的服务器.h:
class MyServer : public QTcpServer
Q_OBJECT
explicit MyServer(QObject *parent = 0);
~MyServer();
protected:
void incomingConnection(qintptr socketDescriptor) Q_DECL_OVERRIDE;
signals:
void stopAll();
;
我的服务器.cpp:
MyServer::MyServer(QObject *parent) : QTcpServer(parent)
MyServer::~MyServer()
emit stopAll();
void MyServer::incomingConnection(qintptr socketDescriptor)
QThread* clientThread = new QThread;
MyClient *client = new MyClient(socketDescriptor, this);
client->moveToThread(clientThread);
connect(clientThread, SIGNAL(started()), client, SLOT(process()));
connect(client, SIGNAL(finished()), clientThread, SLOT(quit()));
connect(this, SIGNAL(stopAll()), client, SLOT(stopFromServer()));
connect(client, SIGNAL(finished()), client, SLOT(deleteLater()));
connect(clientThread, SIGNAL(finished()), clientThread, SLOT(deleteLater()));
clientThread->start();
myclient.h:
class MyClient : public QObject
Q_OBJECT
public:
explicit MyClient(int socketDescriptor, MyServer *server);
~MyClient();
private:
QSslSocket* socket = NULL;
public slots:
void process();
myclient.cpp:
void MyClient::process()
//typical connection things
connect(this->socket, SIGNAL(encrypted()), this, SLOT(ready()));
void MyClient::ready()
connect(socket,SIGNAL(readyRead()),this, SLOT(newData()));
【问题讨论】:
【参考方案1】:我制作了一个软件也使用数据库连接。我没有在我的应用程序上使用 QThread,而是使用 QFuture,线程将从全局线程池中获取(通常线程池的数量将是 CPU 线程的数量)。
并且在访问数据库时,每个池都会有自己的QSqlDatabase。我使用 QThreadStorage 作为 QSqlDatabase 的存储。
static QThreadStorage<QSqlDatabase> mDatabasePool;
....
QSqlDatabase Db::getDatabase()
if(mDatabasePool.hasLocalData())
return mDatabasePool.localData();
else
auto database = QSqlDatabase::addDatabase(SQLDRIVERNAME[DBTYPE], QUuid::createUuid().toString());
mDatabasePool.setLocalData(database);
return database;
所以只有当线程没有连接时才会创建数据库连接。
对于完整的示例项目,您可以查看我的项目:https://github.com/apinprastya/sultan。数据库在 libdb 中,worker QFuture 在 libserver 中。您可以将其用作参考。但我不确定我的设计是否适合你。
【讨论】:
感谢您的回答。我在你的 github 中检查了你的示例和代码,现在我试图理解这个方案:所以,我有很多线程应该使用 DB。如果我需要从这些线程执行查询,我应该在DatabaseService
类中使用QFuture
和QtConcurrent::run
方法executeQuery()
。接下来,executeQuery()
将调用与您完全相同的DatabaseService::getDatabase()
方法来获取QSqlDatabase
实例,然后executeQuery()
将使用获得的QSqlDatabase
实例执行查询。我哪里错了?
是的,你是对的。使用 QFuture,您无需关心线程的生命周期。 QFuture 将使用来自 QThreadPool::globalInstance() 的线程池。您可以通过在全局线程池上设置 setMaxThreadCount() 来增加线程池的数量。当 QFuture 完成任务并向您从数据库查询的主线程数据发送信号时,您还需要一个 QFutureWatcher 作为处理程序。
谢谢,请检查我在问题的 UPD 部分中发布的代码,是否都正确(除了没有QFutureWatcher
,因为我想打电话给@ 987654333@ 并在同一个函数中得到它的结果)?
如果你已经有单独的线程来调用executeQuery,那么使用QFuture 将毫无用处。它将是线程创建另一个线程。你的线程是一个池还是在调用 executeQuery 时创建了一个新线程?
>"It will be thread create another thread" 是的,我也是这么想的。你能澄清你的最后一个问题吗?以上是关于Qt中的数据库连接池的主要内容,如果未能解决你的问题,请参考以下文章
在 QtConcurrent::run 中使用 QSqlDatabase 连接(伪连接池)