一、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数据库多线程的方式,一般可以采用以下步骤:
- 在主线程中打开和创建数据库连接,并创建需要操作的表格。在这里可以使用
QSqlDatabase
和QSqlQuery
等类进行数据库连接和操作。 - 在需要使用多线程读写数据库的场景中,可以考虑使用Qt的信号槽机制,将数据库操作放到独立的线程中执行。具体地,在子线程中创建新的数据库连接并操作数据库(同样可以使用
QSqlDatabase
和QSqlQuery
等类),将查询结果或操作结果通过信号/槽机制传递回主线程并更新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界面。