QT-数据库编程
数据库编程
采用SQLite数据库进行应用开发,SQLite数据库是一种单机(本地)数据库, 不支持远程连接,是一种文件数据库,所有的表、索引等数据库元素全部存储在一个文件里。
官网下载SQLite数据库
官网下载地址:https://www.sqlite.org/download.html
根据你的操作系统(这里是Windows)和架构(32位或64位),找到合适的下载文件。
sqlite-dll-win32-x86-xxxxxx.zip
或sqlite-dll-win64-x64-xxxxxx.zip
(动态链接库文件,用于在应用程序中链接SQLite)sqlite-tools-win32-x86-xxxxxx.zip
或sqlite-tools-win64-x64-xxxxxx.zip
(包含命令行工具如sqlite3.exe
,用于直接操作数据库)
如图:
下载并解压以上文件到同一个目录下,例如 D:\sqlite3
。
在此目录-打开命令窗口,输入sqlite3,返回版本信息等内容,说明安装成功
使用SQLite3命令行工具创建数据库
在命令行中输入 sqlite3
后跟数据库文件名:
sqlite3 mydatabase.db
一旦数据库被创建,可以使用 SQLite 的 .databases 命令来检查它是否在数据库列表中,如下所示:
sqlite>.databases
使用 SQLite .quit 命令退出 sqlite 提示符,如下所示:
sqlite>.quit
执行SQL命令
一旦进入SQLite提示符,就可以执行SQL命令来创建表和执行其他数据库操作:
CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT);
INSERT INTO users (name) VALUES ('hello');SELECT * FROM users;
可视化工具
SQLite Expert是SQLite数据库的可视化管理工具,SQLite Expert安装文件中带有SQLite数据库驱动。使用SQLite Expert可以创建和管理数据库,一个数据库就是一个.db3
的文件。
一、Qt SQL模块
Qt SQL模块提供了一个与平台及数据库无关的访问数据库的接口。
Qt SQL模块中主要的类:
如果要使用Qt SQL模块中的类,就需要再项目文件(.pro文件)中添加QT += sql
代码配置。
二、访问数据库
Qt中访问数据库的步骤如下:
1、创建QSqlDatabase对象
通过添加数据库驱动,并指定使用的驱动类型(如MySQL、PostgreSQL、SQLite等数据库的驱动),建立应用程序与特定数据库之间的连接,从而能够使用Qt的SQL模块API与数据库进行交互。
添加驱动并创建QSqlDatabase对象:
QSqlDatabase database = QSqlDatabase::addDatabase("QSQLITE");
2、设置数据库名称
指定要访问的数据库的名称。如果本目录下没有该文件,则会创建,否则连接该文件。
database.setDatabaseName("数据库名");
3、打开数据库
如果成功返回true,失败返回false。
database.open();
可以用QSqlError::driverText()得到错误信息。database.lastError()会返回QSqlError对象。
bool result = datebase.open();
if (result)
{ qDebug() << "数据库连接成功";
}
else
{QSqlError lastError = database.lastError();qDebug << lastError.driverText();
}
4、执行查询等操作
通过QSqlQuery对象执行sql语句。
QSqlQuery query("select * from student");
query.exec();
5、处理结果
while (query.next()) { //定位到第一行记录qDebug() << query.value("id").toInt() //根据列名查询对应数据<< query.value("name").toString() << query.value("age").toInt();
}
6、清除结果集、关闭数据库
清理 QSqlQuery
对象。每次执行完SQL查询操作后,QSqlQuery
对象都会持有查询结果集。调用 clear()
方法可以清空查询结果集,并释放与此查询相关的内存资源。
关闭 器的连接。当应用程序完成数据库操作后,及时关闭数据库连接可以释放系统资源。
query.clear();
database.close();
7、示例代码
(1)查询示例
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include <QDebug>void testDatabase()
{// 1. 连接 SQLite 数据库(驱动是 QSQLITE)QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");db.setDatabaseName("d:/sqllitedb/test.db3");// 2. 打开数据库if (!db.open()) {qDebug() << "数据库打开失败:" << db.lastError().text();return;}// 3. 执行 SQL 查询QSqlQuery query;if (!query.exec("SELECT empno, ename, salary FROM employee")) {qDebug() << "查询失败:" << query.lastError().text();return;}// 4. 遍历查询结果while (query.next()) {QString empno = query.value(0).toString(); // 第一列QString ename = query.value("ename").toString(); // 也可以用列名QString salary = query.value(2).toString(); // 第三列qDebug() << empno << ename << salary;}// 5. 关闭数据库db.close();
}
(2)添加、删除、修改数据
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include <QDebug>// 打开数据库
QSqlDatabase open()
{QSqlDatabase database = QSqlDatabase::addDatabase("QSQLITE"); // 添加 SQLite 数据库驱动database.setDatabaseName("d:/sqllitedb/test.db3"); // 指定数据库文件路径database.open(); // 打开数据库return database; // 返回数据库对象
}void insert()
{QSqlDatabase database = open(); // 打开数据库QSqlQuery query; // 执行 SQL 语句的对象query.prepare("INSERT INTO employee (name, age) VALUES (?, ?)"); // 使用 ? 占位符预处理 SQLquery.addBindValue("John Doe"); // 绑定第一个参数:namequery.addBindValue(30); // 绑定第二个参数:agebool result = query.exec(); // 执行 SQLif (!result) // 如果失败{QSqlError lastError = database.lastError(); // 获取最后的错误信息qDebug() << lastError.driverText(); // 输出错误原因}database.close(); // 关闭数据库
}void update()
{QSqlDatabase database = open(); // 打开数据库QSqlQuery query; // 执行 SQL 的对象query.prepare("update employee set salary = ? where empno = ?");// 更新语句,两个参数query.addBindValue("John Doe"); // 错误演示:这里本应是工资值query.addBindValue(1); // 员工编号为 1bool result = query.exec(); // 执行 SQLif (!result){QSqlError lastError = database.lastError(); // 获取错误信息qDebug() << lastError.driverText(); // 打印错误}database.close(); // 关闭数据库
}void del()
{QSqlDatabase database = open(); // 打开数据库QSqlQuery query; // SQL 执行对象query.prepare("delete from employee where empno = ?"); // 删除语句query.addBindValue(1); // 删除 empno = 1 的记录bool result = query.exec(); // 执行 SQLif (!result){QSqlError lastError = database.lastError(); // 获取错误信息qDebug() << lastError.driverText(); // 打印错误}database.close(); // 关闭数据库
}
三、QSqlTableModel
在 Qt 中进行数据库编程时,通常会使用模型/视图(Model/View)架构来处理数据和用户界面之间的交互。模型负责管理数据以及数据相关的操作。
对于数据库应用来说,最常用的模型包括:
QSqlTableModel
:适用于表格式的数据,它直接从数据库表读取数据并提供给视图。QSqlQueryModel
:适用于执行 SQL 查询返回的结果集,它可以灵活地展示任意查询结果。
QSqlTableModel模型类通常和QTableView组件构成模型/视图结构,实现数据表的数据显示和编辑。
完成如下项目:
1、打开数据库
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QSqlDatabase> // 数据库类
#include <QSqlTableModel> // 表格模型类QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow; // 前向声明 UI 类
}
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr); // 构造函数~MainWindow(); // 析构函数private slots:void on_actionOpenDB_triggered(); // 菜单动作:打开数据库private:Ui::MainWindow *ui; // UI 指针QSqlDatabase database; // 数据库连接对象QSqlTableModel *model; // 数据表模型(用于显示数据)void openTable(); // 打开并加载表格的方法
};#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFileDialog> // 文件选择对话框
#include <QMessageBox> // 消息提示框
#include <QSqlError> // 数据库错误信息类MainWindow::MainWindow(QWidget *parent): QMainWindow(parent) // 构造函数,继承 QMainWindow, ui(new Ui::MainWindow) // 初始化 UI
{ui->setupUi(this); // 设置 UI
}MainWindow::~MainWindow()
{delete ui; // 释放 UI 内存
}void MainWindow::on_actionOpenDB_triggered()
{QString filename = QFileDialog::getOpenFileName(this, "选择文件","","数据库(*.db)"); // 打开文件选择对话框,选择数据库文件if (filename.isEmpty()) // 如果没有选择文件{return; // 直接返回}database = QSqlDatabase::addDatabase("QSQLITE"); // 添加 SQLite 数据库驱动database.setDatabaseName(filename); // 设置数据库文件名if (!database.open()) // 尝试打开数据库{QSqlError error = database.lastError(); // 获取错误信息qDebug() << error.text(); // 在控制台打印错误QMessageBox::warning(this, "错误", "打开数据库失败"); // 弹出警告提示}else{openTable(); // 如果数据库打开成功,调用 openTable() 打开表}
}void MainWindow::openTable()
{model = new QSqlTableModel(this, database); // 创建数据表模型,绑定到 databasemodel->setTable("employee"); // 设置模型对应的表为 "employee"model->setEditStrategy(QSqlTableModel::OnManualSubmit); // 设置编辑策略:手动提交model->setSort(model->fieldIndex("empno"), Qt::AscendingOrder); // 按 empno 升序排序if (!model->select()) // 执行查询,如果失败{QMessageBox::critical(this, "打开数据表失败", "错误信息:\n" + model->lastError().text()); // 弹出错误提示框return;}
}
2、设置表头
//初始化视图数据
void MainWindow::initData()
{//设置表头数据//orientation:表示要设置的是水平(Qt::Horizontal,即列头)还是垂直(Qt::Vertical,即行头)的表头数据。model->setHeaderData(model->fieldIndex("empno"), Qt::Horizontal, "工号");model->setHeaderData(model->fieldIndex("ename"), Qt::Horizontal, "姓名");model->setHeaderData(model->fieldIndex("gender"), Qt::Horizontal, "性别");model->setHeaderData(model->fieldIndex("birthday"), Qt::Horizontal, "出生日期");model->setHeaderData(model->fieldIndex("province"), Qt::Horizontal, "省份");model->setHeaderData(model->fieldIndex("department"), Qt::Horizontal, "部门");model->setHeaderData(model->fieldIndex("salary"), Qt::Horizontal, "薪水");model->setHeaderData(model->fieldIndex("memo"), Qt::Horizontal, "备注");//设置隐藏列ui->tableView->hideColumn(model->fieldIndex("remark"));
}
3、添加记录
model->setEditStrategy(QSqlTableModel::OnManualSubmit); //添加功能需要改成手动提交
void MainWindow::on_actionAdd_triggered()
{QSqlRecord record = model->record();//获取一条空记录,只有字段定义model->insertRecord(model->rowCount(), record);selection->clearSelection();QModelIndex index = model->index(model->rowCount()-1, 0);selection->setCurrentIndex(index, QItemSelectionModel::Select);//设置选择行
}
4、删除记录
void MainWindow::on_actionDelete_triggered()
{int ok = QMessageBox::warning(this, "删除记录", "确定删除?", QMessageBox::Ok | QMessageBox::Cancel);if (ok == QMessageBox::Ok){QModelIndex index = selection->currentIndex();model->removeRow(index.row());bool result = model->submitAll();if (result){QMessageBox::information(this, "", "删除成功");}else{QMessageBox::information(this, "", "删除失败");}}
}
设置选择模式:
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);//设置选择模式。表格视图这里采用单选模式,在同一时间只能有一个单元格或一行被选中。ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection);ui->tableView->setAlternatingRowColors(true); //交错行变色
}
5、保存/取消
void MainWindow::on_actionSave_triggered()
{bool result = model->submitAll();if (result){QMessageBox::information(this, "保存数据", "保存成功");}else{QMessageBox::information(this, "保存数据", "保存失败");}
}
void MainWindow::on_actionReverse_triggered()
{model->revertAll();
}
6、撤销
void MainWindow::on_action_6_triggered()
{model->revertAll();
}
10、记录排序
void MainWindow::on_radioButtonAsc_clicked()
{model->setSort(ui->comboBoxSort->currentIndex(), Qt::AscendingOrder); // 设置排序:根据 comboBox 当前索引的字段,升序model->select(); // 重新执行查询,应用排序
}void MainWindow::on_radioButtonDesc_clicked()
{model->setSort(ui->comboBoxSort->currentIndex(), Qt::DescendingOrder); // 设置排序:根据 comboBox 当前索引的字段,降序model->select(); // 重新执行查询,应用排序
}void MainWindow::on_comboBoxSort_currentIndexChanged(int index)
{if (ui->radioButtonAsc->isChecked()) // 如果升序按钮被选中{model->setSort(ui->comboBoxSort->currentIndex(), Qt::AscendingOrder); // 设置为升序}else if (ui->radioButtonDesc->isChecked()) // 如果降序按钮被选中{model->setSort(ui->comboBoxSort->currentIndex(), Qt::DescendingOrder); // 设置为降序}model->select(); // 重新执行查询,应用排序
}
11、记录过滤
QSqlTableModel的setFilter()函数可设置记录过滤条件
void QSqlTableModel::setFilter(const QString &filter);
字符串类型的参数filter是过滤条件,实际上是select语句里where子句的条件。
void MainWindow::on_radioButtonMale_clicked()
{model->setFilter(" gender='男' "); // 设置过滤条件:只显示性别为“男”的记录ui->statusbar->showMessage(QString("记录条数:%1").arg(model->rowCount())); // 在状态栏显示当前筛选后的记录条数
}void MainWindow::on_radioButtonFemale_clicked()
{model->setFilter("gender='女'"); // 设置过滤条件:只显示性别为“女”的记录ui->statusbar->showMessage(QString("记录条数:%1").arg(model->rowCount())); // 在状态栏显示当前筛选后的记录条数
}void MainWindow::on_radioButtonAll_clicked()
{model->setFilter(""); // 清空过滤条件,显示所有记录ui->statusbar->showMessage(QString("记录条数:%1").arg(model->rowCount())); // 在状态栏显示记录条数
}