使用Qt操作SQLite数据库
目录
- 一、开发成果
- 二、环境配置与基础概念
- 1. 引入SQL模块
- 2. SQLite数据库特性
- 三、数据库连接与操作流程
- 1. 创建并连接数据库
- 2. 执行SQL语句
- 3. 查询与遍历数据
- 四、进阶操作与最佳实践
- 1. 事务处理
- 2. 错误处理
- 3. 使用模型/视图架构
- 五、完整代码示例(学生人员管理)
- 1.mainwindow.h
- 2.mainwindow.cpp
- 3.main.cpp
- 六、常见问题与优化建议
- 1. 连接管理:
- 2. 性能优化:
一、开发成果
二、环境配置与基础概念
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_OBJECTpublic: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 modelm_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开发实战持续更新中。