我正在做一个使用QSqlDatabase的项目。现在我使用QtConcurrent(QFuture)来执行任何SQL命令。
现在,每个使用QFuture运行的新命令都会创建与我的Mysql服务器的新QSqlDatabase连接。我相信任何与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的一些内容?
答案 0 :(得分:0)
首先,一个不起作用的想法:将连接添加为线程本身的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;
}