我正在做一个使用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的东西?
发布于 2017-05-18 12:53:21
首先,一个无法工作的想法:将连接添加为线程本身的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;
} https://stackoverflow.com/questions/44042694
复制相似问题