gpt4 book ai didi

c++ - QThreadPool 上的 QSqlDatabase 池

转载 作者:太空宇宙 更新时间:2023-11-04 13:01:31 27 4
gpt4 key购买 nike

我正在做一个使用 QSqlDatabase 的项目。现在我正在使用 QtConcurrent (QFuture) 来执行任何 SQL 命令。

现在,使用 QFuture 运行的每个新命令都会创建新的 QSqlDatabase 连接到我的 Mysql 服务器。我相信任何与 Mysql 服务器的新连接都会对握手产生不利影响。因此,我计划创建一个 QSqlDatabase 池,并且从文档 QSqlDatabase 中只能由创建它的线程使用。

所以,我的想法是制作一个 QMap 池,其中 int 是线程 ID,QString 是连接名称。因此,当我想使用 qfuture 从线程池启动线程时,只需从 QMap 池中获取连接名称并获取 QSqlDatabase(此 QSqlDatabase 已连接到服务器)。

示例代码:

//this is static variable
QMap<int, QString> pool;
.....

//At the beginning of sql command to execute
if(pool.contains((int)QThread::currentThreadId()) {
db = QSqlDatabase::database(pool[(int)QThread::currentThreadId()]);
} else {
QString key = "someunique" + QString::number((int)QThread::currentThreadId());
db = QSqlDatabase::add(key)
... // some Qsql connection code
pool.insert((int)QThread::currentThreadId(), key);
}

也许我上面的代码行不通,但我想问的是:我的想法行得通吗?还是我错过了有关 QSqlDatabase 的某些信息?

最佳答案

首先,一个行不通的想法:将连接添加为线程本身的 QObject 属性。它不会工作,因为 QObject 属性系统不是线程安全的。

一个可行的简单想法是使用 QThreadStorage 将数据库连接存储在线程本地存储中。当池中的线程消失时,它将自动处理:

QThreadStorage<QSqlDatabase> connections;

QSqlDatabase newConnection();

QSqlDatabase getConnection() {
auto & connection = connections.localData();
if (! connection.isValid())
connection = newConnection();
return connection;
}

只要您序列化对池的并发访问,您的想法就会奏效。您还需要确保在线程完成时清理连接。您也可以直接使用 QThread 指针,而不是使用 id。无需通过字符串键引用连接,您可以直接保存它们,因为它们是值。 QSqlDatabase 是句柄,就像文件句柄一样。

QReadWriteLock poolLock;
QMap<QThread*, QSqlDatabase> pool;

struct ConnectionDropper : public QObject {
void drop() {
QWriteLocker writeLock{&poolLock};
pool.remove(qobject_cast<QThread*>(sender()));
}
}
Q_GLOBAL_STATIC(Dropper, dropper);

QSqlDatabase newConnection();

QSqlDatabase getConnection() {
auto thread = QThread::currentThread();
QReadLocker readLock{&poolLock};
auto it = std::find(pool.begin(), pool.end(), thread);
if (it != pool.end())
return it.value();
readLock.unlock();
// connecting can take some time, so don't lock the pool while it happens
auto conn = newConnection();
// Unique connections to functors are not implemented, thus we need an object.
QObject::connect(thread, &QThread::finished, &*dropper,
&ConnectionDropper::drop, Qt::DirectConnection | Qt::UniqueConnection);
QWriteLocker writeLock{&poolLock};
pool.insert(thread, conn);
return conn;
}

关于c++ - QThreadPool 上的 QSqlDatabase 池,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44042694/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com