记录QT QSqlDatabase SQLite 多线程使用时报错..

首先QSqlDatabase同一个实例, 不能多线程使用.

如果多线程使用,需要给每个线程创建一个QSqlDatabase实例, 一般是用Map维护各个线程实例链接, key是线程ID, value就是QSqlDatabase指针,例如:

static QMap<Qt::HANDLE,QSqlDatabase*> mapInstance;

Key(Qt::HANDLE)是: QThread::currentThreadId() 返回值, Value是: QSqlDatabase实例指针。

建议写一个全局可以使用的获取QSqlDatabase实例静态方法,例如:

class DBHelper
{
public:
    static DBHelper* GetInstance() {
        if(!databaseMap.contains(QThread::currentThreadId())) {
            databaseMap.insert(QThread::currentThreadId(), new DBHelper());
        }
        return databaseMap[QThread::currentThreadId()];
    }
    DBHelper() {
        //创建数据库链接并指定链接名称
        this->database = QSqlDatabase::addDatabase("QSQLITE", QString::number((int)QThread::currentThreadId()));
        this->database.setDatabaseName("D:/work/svnwork/ProbeTable/probe.db");
        this->database.open();//是否打开成功判断
    }

    void query(QString sql) {
        QSqlQuery sql_query(this->database);//必须指定当前数据库实例
        qDebug() << sql_query.exec(sql);//是否执行成功判断
    }
private:
    static QMap<Qt::HANDLE, DBHelper*> databaseMap;//所有数据库链接,key: 线程ID, value 数据库链接实例指针
    QSqlDatabase database;//当前线程数据库链接
};

为了更方便使用, QSqlDatabase通过DBHelper 封装了一层,添加了query方法。
需要注意的点是在通过QSqlDatabase::addDatabase函数为每个线程创建链接时,需要给每个线程分配一个连接名称:
QSqlDatabase::addDatabase("QSQLITE", QString::number((int)QThread::currentThreadId()));

这里直接用的当前线程ID当的链接名称, 不一定必须是线程ID,只要在全局中是唯一的就可以。

如果没有指定线程名称, 默认走的是QSqlDatabase内部的默认名称,也就是defaultConnection,这是addDatabase函数原型:

    static QSqlDatabase addDatabase(QSqlDriver* driver,
                                 const QString& connectionName = QLatin1String(defaultConnection));

如果在调用addDatabase的时候没有指定链接名称, 很有可能后创建的QSqlDatabase 链接覆盖掉之前的,。(因为没指定链接名称时,走的都是默认链接名称defaultConnection)。就会在第二次调用addDatabase函数时出现错误:

QSqlDatabasePrivate::removeDatabase: connection 'qt_sql_default_connection' is still in use, all queries will cease to work.
QSqlDatabasePrivate::addDatabase: duplicate connection name 'qt_sql_default_connection', old connection removed.
QSqlDatabasePrivate::database: requested database does not belong to the calling thread.
QSqlQuery::exec: database not open
SQLINFO:  QSqlError("", "Driver not loaded", "Driver not loaded")

 

最后在使用DBHelper前,声明静态变量databaseMap,像这样:

main.cpp:

QMap<Qt::HANDLE, DBHelper*> DBHelper::databaseMap;

int main(void){
  //...  
  return 0;  
}

 

posted @ 2022-08-18 08:58  耿明岩  阅读(2008)  评论(0编辑  收藏  举报
希望能帮助到你,顺利解决问题! ...G(^_−)☆