使用Qt操作SQLite数据库

一、开发成果

在这里插入图片描述

二、环境配置与基础概念

1. 引入SQL模块

在Qt项目文件(.pro)中添加SQL模块支持,这是操作数据库的前提:

QT += sql

该语句启用了Qt的数据库驱动功能,支持SQLite、MySQL等数据库。

2. SQLite数据库特性

SQLite无需独立服务器进程,数据以单个文件形式存储(扩展名通常为.db),支持事务、零配置,适合嵌入式和小型应用。其轻量级特性使其成为Qt开发中的首选数据库之一。

三、数据库连接与操作流程

1. 创建并连接数据库
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");  // 指定驱动类型
db.setDatabaseName("mydatabase.db");                     // 设置数据库文件路径
if (!db.open()) {
    qDebug() << "连接失败:" << db.lastError().text();
    return;
}
  • 关键点:
    • 使用QSQLITE驱动标识符。
    • setDatabaseName()可指定绝对路径或内存数据库(如:memory:)。
    • 若文件不存在,SQLite会自动创建新数据库。
2. 执行SQL语句

通过QSqlQuery类执行SQL命令:

QSqlQuery query;
// 创建表
query.exec("CREATE TABLE IF NOT EXISTS users ("
          "id INTEGER PRIMARY KEY AUTOINCREMENT, "
          "name TEXT NOT NULL, age INT)");

// 插入数据(预编译防SQL注入)
query.prepare("INSERT INTO users (name, age) VALUES (:name, :age)");
query.bindValue(":name", "Alice");
query.bindValue(":age", 30);
if (!query.exec()) {
    qDebug() << "插入失败:" << query.lastError().text();
}
  • 方法对比:
    • 直接执行exec(“SQL语句”)适合简单操作。
    • prepare() + bindValue()更安全,支持参数绑定,防止SQL注入。
3. 查询与遍历数据
query.exec("SELECT * FROM users");
while (query.next()) {
    int id = query.value("id").toInt();
    QString name = query.value(1).toString();  // 通过字段名或索引获取
    int age = query.value(2).toInt();
    qDebug() << id << name << age;
}
  • 注意:
    • query.value()返回QVariant类型,需转换为具体数据类型。
    • 使用query.record()可获取字段元数据(如字段名、类型)。

四、进阶操作与最佳实践

1. 事务处理

确保数据一致性:

db.transaction();  // 开启事务
// 执行多条SQL操作
if (所有操作成功) {
    db.commit();    // 提交事务
} else {
    db.rollback();  // 回滚事务
}

事务适用于批量插入、更新等场景,避免部分操作失败导致数据不一致。

2. 错误处理

每次操作后检查错误:

if (!query.exec()) {
    qDebug() << "错误信息:" << query.lastError().text();
    qDebug() << "执行的SQL:" << query.lastQuery();
}

通过lastError()获取详细错误描述,便于调试。

3. 使用模型/视图架构

Qt提供QSqlTableModel和QSqlQueryModel,实现数据库与UI组件的绑定:

QSqlTableModel *model = new QSqlTableModel(this);
model->setTable("users");
model->select();
QTableView *view = new QTableView;
view->setModel(model);

通过模型类可自动同步数据到表格视图,简化开发。

五、完整代码示例(学生人员管理)

1.mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QWidget>
#include <QVBoxLayout>
#include <QPushButton>
#include <QTableView>
#include <QLineEdit>
#include <QComboBox>
#include <QSqlDatabase>
#include <QSqlError>
#include <QSqlQuery>
#include <QSqlTableModel>
#include <QMessageBox>

class DatabaseManager {
public:
    static DatabaseManager* getInstance() {
        if (!instance) {
            instance = new DatabaseManager();
        }
        return instance;
    }

    QSqlDatabase getDatabase() const {
        return db;
    }

private:
    DatabaseManager() {
        db = QSqlDatabase::addDatabase("QSQLITE");
        db.setDatabaseName("students.db");

        if (!db.open()) {
            QMessageBox::critical(nullptr, "Cannot open database",
                                  "Unable to establish a database connection.\n"
                                  "This example needs SQLite support. Please read "
                                  "the Qt SQL driver documentation for information how "
                                  "to build it.\n\n"
                                  "Click Cancel to exit.", QMessageBox::Cancel);
        } else {
            createTable();
        }
    }

    ~DatabaseManager() {
        db.close();
    }

    void createTable() {
        QSqlQuery query;
        query.exec("CREATE TABLE IF NOT EXISTS students (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER, gender TEXT)");
    }

    static DatabaseManager* instance;
    QSqlDatabase db;
};

class MainWindow : public QWidget

{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
private:
    void setHeadersForQueryModel(QSqlQueryModel *queryModel);

    QSqlTableModel *m_model;
    QSqlQueryModel *m_queryModel;
    QTableView *m_tableView;
    QLineEdit *m_nameEdit;
    QLineEdit *m_ageEdit;
    QComboBox *m_genderCombo;
};

#endif // MAINWINDOW_H

2.mainwindow.cpp

#include "mainwindow.h"

DatabaseManager* DatabaseManager::instance = nullptr;
MainWindow::MainWindow(QWidget *parent)
    : QWidget(parent),
    m_model(new QSqlTableModel(this))
{
    QVBoxLayout *layout = new QVBoxLayout(this);

    m_tableView = new QTableView(this);
    layout->addWidget(m_tableView);

    QPushButton *insertButton = new QPushButton("新增", this);
    QPushButton *deleteButton = new QPushButton("删除", this);
    QPushButton *updateButton = new QPushButton("修改", this);
    QPushButton *queryButton = new QPushButton("查询", this);

    QHBoxLayout *buttonLayout = new QHBoxLayout();
    buttonLayout->addWidget(insertButton);
    buttonLayout->addWidget(deleteButton);
    buttonLayout->addWidget(updateButton);
    buttonLayout->addWidget(queryButton);
    layout->addLayout(buttonLayout);

    m_nameEdit = new QLineEdit(this);
    m_ageEdit = new QLineEdit(this);
    m_genderCombo = new QComboBox(this);
    m_genderCombo->addItem("男");
    m_genderCombo->addItem("女");

    QHBoxLayout *inputLayout = new QHBoxLayout();
    inputLayout->addWidget(m_nameEdit);
    inputLayout->addWidget(m_ageEdit);
    inputLayout->addWidget(m_genderCombo);
    layout->addLayout(inputLayout);

    connect(insertButton, &QPushButton::clicked, [this]() {
        QString name = m_nameEdit->text();
        int age = m_ageEdit->text().toInt();
        QString gender = m_genderCombo->currentText();

        QSqlQuery query;
        query.prepare("INSERT INTO students (name, age, gender) VALUES (:name, :age, :gender)");
        query.bindValue(":name", name);
        query.bindValue(":age", age);
        query.bindValue(":gender", gender);

        if (!query.exec()) {
            QMessageBox::warning(this, "Error", "Failed to insert record.");
        } else {
            m_model->select();
        }
    });

    connect(deleteButton, &QPushButton::clicked, [this]() {
        QModelIndex index = m_tableView->currentIndex();
        if (index.isValid()) {
            m_model->removeRow(index.row());
            m_model->submitAll();
        }
    });

    connect(updateButton, &QPushButton::clicked, [this]() {
        QModelIndex index = m_tableView->currentIndex();
        if (index.isValid()) {
            QString name = m_nameEdit->text();
            int age = m_ageEdit->text().toInt();
            QString gender = m_genderCombo->currentText();

            m_model->setData(m_model->index(index.row(), 1), name);
            m_model->setData(m_model->index(index.row(), 2), age);
            m_model->setData(m_model->index(index.row(), 3), gender);
            m_model->submitAll();
        }
    });

    connect(queryButton, &QPushButton::clicked, [this]() {
        QString name = m_nameEdit->text();
        if (!name.isEmpty()) {
            m_queryModel->setQuery(QString("SELECT * FROM students WHERE name='%1'").arg(name));
            setHeadersForQueryModel(m_queryModel);
            m_tableView->setModel(m_queryModel);
        } else {
            m_model->select();
            m_tableView->setModel(m_model);
        }
    });

    // Set headers for the table model
    m_model->setHeaderData(0, Qt::Horizontal, QObject::tr("ID"));
    m_model->setHeaderData(1, Qt::Horizontal, QObject::tr("姓名"));
    m_model->setHeaderData(2, Qt::Horizontal, QObject::tr("年龄"));
    m_model->setHeaderData(3, Qt::Horizontal, QObject::tr("性别"));

    m_queryModel = new QSqlQueryModel(this);
    m_model->setTable("students");
    m_model->select();

    m_tableView->setModel(m_model);

}

MainWindow::~MainWindow()
{
    delete m_model;
    delete m_queryModel;
    delete m_tableView;
    delete m_nameEdit;
    delete m_ageEdit;
    delete m_genderCombo;
}

void MainWindow::setHeadersForQueryModel(QSqlQueryModel *queryModel)
{
    queryModel->setHeaderData(0, Qt::Horizontal, QObject::tr("ID"));
    queryModel->setHeaderData(1, Qt::Horizontal, QObject::tr("姓名"));
    queryModel->setHeaderData(2, Qt::Horizontal, QObject::tr("年龄"));
    queryModel->setHeaderData(3, Qt::Horizontal, QObject::tr("性别"));
}
3.main.cpp
#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    DatabaseManager::getInstance()->getDatabase();
    MainWindow w;
    w.show();
    return a.exec();
}

六、常见问题与优化建议

1. 连接管理:
  • 使用QSqlDatabase::contains()检查连接是否已存在,避免重复创建。
  • 多线程环境下需为每个线程创建独立连接。
2. 性能优化:
  • 批量操作时启用事务,减少磁盘I/O次数。
  • 使用索引加速查询,避免全表扫描。
    更多Qt开发实战持续更新中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

半青年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值