首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >QSqlDatabase池在QThreadPool上

QSqlDatabase池在QThreadPool上
EN

Stack Overflow用户
提问于 2017-05-18 08:38:41
回答 1查看 794关注 0票数 2

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

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

因此,我的想法是创建一个QMap池,其中int是线程id,QString是连接名。因此,当我想使用qfuture从线程池启动线程时,只需从QMap池获取连接名并获取QSqlDatabase (这个QSqlDatabase已经连接到服务器)。

样本代码:

代码语言:javascript
复制
//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的东西?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-05-18 12:53:21

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

一个简单的方法就是使用QThreadStorage将数据库连接存储在线程本地存储中。然后,当池中的线程离开时,它将被自动释放:

代码语言:javascript
复制
QThreadStorage<QSqlDatabase> connections;

QSqlDatabase newConnection();

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

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

代码语言:javascript
复制
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;
}  
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44042694

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档