一、QSqlDatabase概述
       QSqlDatabase提供了一系列的接口用于访问操作数据库,包括连接数据库,输入sql语句等。
QSqlDatabase的实例表示着一个对数据库的连接。该连接通过一个受支持的数据库驱动程序(从QSqlDriver派生)提供对数据库的访问。另外,可以从QSqlDriver子类化自己的数据库驱动程序。(如何创建自己的驱动,详见其他文档)Qt支持的数据库有很多,自己首先接触到的是QODBC(用于sql server)。另外还有QSQLITE、QDB2、QIBASE、QMYSQL等。

二、QSqlDatabase模块的使用
QSqlDatabase类处理与数据库的连接,要使用这个类,头文件需要导入QSqlDatabase库:

#include <QSqlDatabase>
在qmake.pro文件中加入SQL数据库支持:

QT += sql
    这个类提供了以下公共方法:QSqlDatabase::addDatabase、QSqlDatabase::removeDatabase和QSqlDatabase::database函数都是线程安全的。但是open不是线程安全的,所以在open时需要加上锁。

三、多线程操作不同的链接

在Qt中使用SQLite数据库多线程的方式,一般可以采用以下步骤:

  1. 在主线程中打开和创建数据库连接,并创建需要操作的表格。在这里可以使用QSqlDatabaseQSqlQuery 等类进行数据库连接和操作。
  2. 在需要使用多线程读写数据库的场景中,可以考虑使用Qt的信号槽机制,将数据库操作放到独立的线程中执行。具体地,在子线程中创建新的数据库连接并操作数据库(同样可以使用 QSqlDatabaseQSqlQuery 等类),将查询结果或操作结果通过信号/槽机制传递回主线程并更新UI界面。

以下是一个示例代码,演示如何在多线程中使用SQLite数据库:

// 新建一个线程类,用于执行数据库操作
 class DBThread : public QThread
 {
     Q_OBJECTpublic:
     explicit DBThread(QObject *parent = 0) : QThread(parent) {}signals:
     void resultReady(const QString &result);protected:
     void run() override {
         // 在子线程中打开数据库连接    QSqlDatabase *pdb=NULL;
        {             QMutexLocker locker(&g_mutex);
           QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE","唯一的连接名,需要自己设置");
             db.setDatabaseName("myDB.db");          pdb=&db;
          if (!db.open()) {
               emit resultReady("Error: failed to connect database.");
                return;
              } }
        // 在子线程中执行数据库操作
         QSqlQuery query(*pdb);
         if (query.exec("SELECT * FROM myTable")) {
             QString result;
             while (query.next()) {
                 QString name = query.value(0).toString();
                 int age = query.value(1).toInt();
                 result += QString("Name: %1, Age: %2\n").arg(name).arg(age);
             }
             emit resultReady(result);
         } else {
             emit resultReady("Error: failed to execute query.");
         }        // 在子线程中关闭数据库连接
         db.close();
     }
 };// 主窗口类,用于与UI界面交互和更新结果
 class MainWindow : public QMainWindow
 {
     Q_OBJECTpublic:
     explicit MainWindow(QWidget *parent = 0) : QMainWindow(parent)
     {
         // 创建操作按钮并绑定槽函数
         QPushButton *queryButton = new QPushButton(tr("Query"), this);
         connect(queryButton, &QPushButton::released, this, &MainWindow::handleQuery);        // 创建文本框并添加到主窗口
         outputWidget = new QTextEdit(this);
         outputWidget->setReadOnly(true);
         setCentralWidget(outputWidget);
         statusBar();        // 将主窗口与DBThread线程的信号/槽连接起来
         thread = new DBThread(this);
         connect(thread, &DBThread::finished, thread, &QObject::deleteLater);
         connect(thread, &DBThread::resultReady, this, &MainWindow::showResult);
     }private slots:
     void handleQuery()
     {
         // 启动一个新的线程执行数据库操作
         thread->start();
     }    void showResult(const QString &result)
     {
         // 在主线程中更新UI界面
         outputWidget->setPlainText(result);
     }private:
     DBThread *thread;
     QTextEdit *outputWidget;
 };

在上述示例代码中,我们创建了一个 DBThread 类用于在子线程中执行数据库操作,该类继承自 QThread 类。在主窗口类的成员函数 handleQuery() 中,我们启动了一个新的 DBThread 线程,并在主窗口类的成员函数 showResult() 中更新UI界面。

当在子线程中执行完毕后,通过 emit 语句发射信号通知主线程界面需要更新,这里使用了 resultReady() 信号。主窗口类将这个信号与自己的槽函数 showResult() 绑定起来,以接收子线程发送的结果并更新UI界面。