我的解决方案是将QtConcurrent 与不会破坏其线程的自定义线程池一起使用。在每个线程的上下文中,我创建了一个专用的QSqlDatabase 连接,并以该线程的名称作为连接的名称,这样每个线程每次需要与数据库通信时都会获取相同的连接。
设置:
mThreadPool = new QThreadPool(this);
// keep threads indefinitely so we don't loose QSqlDatabase connections:
mThreadPool->setExpiryTimeout(-1);
mThreadPool->setMaxThreadCount(10); /* equivalent to 10 connections */
qDebug() << "Maximum connection count is "
<< mThreadPool->maxThreadCount();
析构函数:
// remove the runnables that are not yet started
mThreadPool->clear();
// wait for running threads to finish (blocks)
delete mThreadPool;
返回未来的示例 API 实现,可用于在数据库可用时从数据库中获取数据:
QFuture<QList<ArticleCategory> *>
DatabaseService::fetchAllArticleCategories() const
{
return QtConcurrent::run(mThreadPool,
&DatabaseService::fetchAllArticleCategoriesWorker, mConnParameters);
}
请注意,我的解决方案不管理它创建的对象。
调用代码需要管理该内存(上面返回的QList)。
附带线程工作者函数:
QList<ArticleCategory> *DatabaseService::fetchAllArticleCategoriesWorker(const DatabaseConnectionParameters &dbconparams)
{
try {
setupThread(dbconparams);
} catch (exceptions::DatabaseServiceGeneralException &e) {
qDebug() << e.getMessage();
return nullptr;
}
QString threadName = QThread::currentThread()->objectName();
QSqlDatabase db = QSqlDatabase::database(threadName, false);
if (db.isValid() && db.open()) {
QSqlQuery q(db);
q.setForwardOnly(true);
// ...
}
// else return nullptr
// ...
}
如果你注意到了,setupThread 总是在工作线程开始时被调用,它基本上为调用线程准备数据库连接:
void DatabaseService::setupThread(const DatabaseConnectionParameters &connParams)
{
utilities::initializeThreadName(); // just sets a QObject name for this thread
auto thisThreadsName = QThread::currentThread()->objectName();
// check if this thread already has a connection to a database:
if (!QSqlDatabase::contains(thisThreadsName)) {
if (!utilities::openDatabaseConnection(thisThreadsName, connParams))
{
qDebug() << "Thread"
<< thisThreadsName
<< "could not create database connection:"
<< QSqlDatabase::database(thisThreadsName, false).lastError().text();
}
else
{
qDebug() << "Thread"
<< thisThreadsName
<< "successfully created a database connection.";
}
}
}