Qt中SQLite数据库的使用
在Qt中如何使用数据库存储数据?如何对数据库中的数据进行增删查改?六千字代码加图片,一文搞定!
一、安装SQLite
在Qt6中,不再支持 SQLite2,只支持 SQLite3 。因此,有两种方式使用 SQLite,一种是在 SQLite 官网安装 SQLite3,另外一种是直接安装 SQLite Expert。
SQLite Expert 内置了 SQLite。这意味着用户在安装 SQLite Expert 后,无需单独安装 SQLite 即可使用其全部功能。内置的 SQLite 引擎使得用户能够直接创建、管理和操作 SQLite 数据库,而不必担心额外的配置和兼容性问题。点击如下链接即可安装:
SQLite administration | SQLite Expert
二、连接SQL
1. 修改项目配置文件(.pro文件)
如果需要在Qt项目中使用数据库编程功能,需要将Qt SQL模块添加到项目中,也就是需要在项目配置文件中增加下面一句:
QT += sql
2. 修改头文件(.h文件)
如果要使用一些常用的Qt SQL类,在头文件中则需要添加如下代码:
#include <QtSql>
3. 添加数据库连接(.cpp文件)
QSqlDatabase 类用于建立与数据库的连接,而 QSqlDatabase 对象就表示这种连接。例如接下来说的 QSqlQuerryModel 模型类查询数据库时,就必须设置它。它的函数原型定义如下:
QSqlDatabase QSqlDatabase::addDatabase(const QString &type, const QString &connectionName = QLatinString(defaultConnection))
- type:连接的数据库类型;
- connectionName:所创建的数据库连接名称,若不设置则使用默认的数据库连接名称"qt_default_connection"
举个例子:
//打开数据库
void MainWindow::on_actOpenDB_triggered()
{
QString aFile = QFileDialog::getOpenFileName(this,"选择文件","","SQLite数据库(*.db3)");
if (aFile.isEmpty())
return;
QSqlDatabase DB = QSqlDatabase::addDatabase("QSQLITE"); //添加 SQLITE数据库驱动
DB.setDatabaseName(aFile); //设置数据库文件
if (DB.open()) //成功打开数据库
selectData(); // 展示数据库数据
else
QMessageBox::warning(this, "错误", "打开数据库失败");
}
这段代码中,当在打开的文件对话框中选中一个 .db3 文件并打开后,就成功地创建了一个SQLite数据库连接。
三、关于Qt SQL的模型类
了解这些内容之前,我们必须知道各个模型类的继承关系。
1. QSqlQuerryModel
这是一个表示SQL查询结果数据的模型类,它通过设置select语句查询数据库的数据。因此,这个模型类的数据是只读的,不可修改。
要想将数据库中查询到的数据作为 QSqlQuerryModel 的数据源,就必须使用 setQuery() 函数,其函数定义如下:
void QSqlQueryModel::setQuery(const QString &query, const QSqlDatabase &db = QSqlDatabase())
- query:一条完整的select语句,用来查询数据库;
- db:数据库连接 ,若不指定,则使用程序默认数据库连接
举个例子:
//查询数据
void MainWindow::selectData()
{
QSqlQueryModel qryModel = new QSqlQueryModel(this);
qryModel->setQuery("SELECT empNo, Name, Gender, Birthday, Province, Department, Salary FROM employee ORDER BY empNo", DB);
ui->tableView->setModel(qryModel);
}
这样在视图中就可通过 QSqlQuerryModel 模型显示数据库中的数据。
2. QSqlTableModel
表示单个数据表的模型类。直接设置一个数据表的名称,就可以获取数据表的全部记录。与QSqlQuerryModel 不同的是,它的数据是可编辑的。其函数定义如下:
QSqlTableModel (QObject *parent = nullptr, const QSqlDatabase &db = QSqlDatabase())
举个例子:
// 打开数据表
void MainWindow::openTable()
{
QSqlTableModel tabModel = new QSqlTableModel(this, DB);
tabModel->setTable("employee"); //选择一个数据表作为数据源
tabModel->setEditStrategy(QSqlTableModel::OnManualSubmit); //设置为临时保存策略
if (!(tabModel->select())) { //查询数据失败
QMessageBox::critical(this, "错误信息", "打开数据表错误,错误信息:\n" + tabModel->lastError().text());
return;
}
ui->tableView->setModel(tabModel);
}
// 保存修改
void MainWindow::on_actSubmit_triggered()
{
tabModel->submitAll();
}
// 取消修改
void MainWindow::on_actRevert_triggered()
{
tabModel->revertAll();
}
与 QSqlQuerryModel 不同的是,我们无须使用select语句直接使用内置的 select() 方法即可。而且当在tableView视图中修改了某项数据后,可以通过 submitAll() 将数据的修改提交到数据库。
3. QSqlRelationalTableModel
它可以作为具有编码字段的数据表的模型类。这是什么意思?
如上面三张表,我们希望将第一张表的 majorID 字段与第二章表的 majorID 字段连接,然后将第一张表的majorID“编码”为第二张表的major。同理第三张表也是如此。
那么这种操作就需要用到 QSqlRelationalTableModel ,其函数定义如下:
QSqlRelationalTableModel (QObject *parent = nullptr, const QSqlDatabase &db = QSqlDatabase())
如何设置上述的SQL的外键关系?主要用到一个函数 setRelation() :
void QSqlRelationalTableModel::setRelation(int column, const QSqlRelation &relation)
QSqlRelation(const QString &tableName, const QString &indexColumn, const QString &displayColumn)
- column:外键字段的字段序号;
- relation:一个 QSqlRelation 对象
- tableName:编码表表名
- indexColumn:外键字段名
- displayColumn:编码表中代码含义字段名称
举个例子:
// 打开数据表
void MainWindow::openTable()
{
QSqlRelationalTableModel tabModel = new QSqlRelationalTableModel(this, DB);
tabModel->setTable("studInfo");
tabModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
ui->tableView->setModel(tabModel);
//设置外键关系--QSqlRelation("另一个表名","另一个表里的外键","另一个表里的字段名称"))
tabModel->setRelation(tabModel->fieldIndex("departID"), QSqlRelation("departments","departID","department")); //学院
tabModel->setRelation(tabModel->fieldIndex("majorID"), QSqlRelation("majors","majorID","major")); //专业
//为关系型字段设置默认代理组件
ui->tableView->setItemDelegate(new QSqlRelationalDelegate(ui->tableView));
}
这样,当我们用tableView显示上述数据库表一内容时,就会自动编码majorID和departID。而且QSqlRelationalTableModel的默认代理组件也会对单元格进行委托代理,实现类似QComboBox样式的编辑效果。
四、QSqlQuery类
在上述的模型类当中,我们只能双击单元格修改、再点击提交的方式修改数据库中的数据。这样显得很呆!而 QSqlQuery 是能运行任何 SQL 语句的类,如select、insert、update、delete等常用SQL语句。
但是,QSqlQuery 并没有父类,与上述模型类没有直接继承关系,因此查询到的数据并不能作为 模型/视图 结构中的数据模型,只能作为一个数据集使用。
几个重要的接口函数如下:
bool prepare() //设置准备运行的SQL语句
void bindValue() // 绑定prepare()中的SQL语句含有的参数
void exec() //运行设置好的SQL语句
QString executedQuery() //返回上一次成功执行的SQL语句
注:若 prepare() 函数中没有参数,可以直接在 exec() 函数中放置SQL语句直接执行。
举个例子:
// tableView上双击,编辑当前记录
void MainWindow::on_tableView_doubleClicked(const QModelIndex &index)
{
int curRecNo = index.row();
updateRecord(curRecNo);
}
// 更新一条记录
void MainWindow::updateRecord(int recNo)
{
QSqlRecord curRec = qryModel->record(recNo); //获取数据模型的一条记录
int empNo = curRec.value("EmpNo").toInt(); //获取员工工号这个主键
QSqlQuery query;
query.prepare("select * from employee where EmpNo = :ID");
query.bindValue(":ID",empNo);
query.exec();
if (!query.isValid())
return;
TDialogData *dataDialog = new TDialogData(this); //创建对话框
if (dataDialog->exec() == QDialog::Accepted)
{
QSqlRecord recData = dataDialog->getRecordData(); //获得对话框返回的记录
query.prepare("update employee set Name=:Name, Gender=:Gender,"
" Birthday=:Birthday, Province=:Province,"
" Department=:Department, Salary=:Salary,"
" Memo=:Memo, Photo=:Photo "
" where EmpNo = :ID");
query.bindValue(":Name", recData.value("Name"));
query.bindValue(":Gender", recData.value("Gender"));
query.bindValue(":Birthday", recData.value("Birthday"));
query.bindValue(":Province", recData.value("Province"));
query.bindValue(":Department", recData.value("Department"));
query.bindValue(":Salary", recData.value("Salary"));
query.bindValue(":Memo", recData.value("Memo"));
query.bindValue(":Photo", recData.value("Photo"));
query.bindValue(":ID", empNo);
if (!query.exec())
QMessageBox::critical(this, "错误", "记录更新错误\n" + query.lastError().text());
else
//数据模型重新查询数据,更新tableView显示
qryModel->setQuery(qryModel->query().executedQuery());
}
delete dataDialog; //删除对话框
}
注意:在重新查询数据时,下列写法是错误的:
//query.executedQuery()返回上一条成功执行的SQL语句
qryModel->setQuery(query.executedQuery());
因为query对象为QSqlQuery类,它的上一条成功执行的SQL语句不一定是select子句。而qryModel对象为QSqlQueryModel类,它只能执行select子句,否则会导致编译错误。
当我们再次双击单元格想要修改某一项数据时,就会打开一个 “更新记录” 的对话框。对话框将获取到的信息作为 bindValue() 函数的参数,最后用 exec() 执行后,数据库中的数据就会改变。当然,想要界面上的信息也发生改变,数据模型必须重新查询数据库中的数据。
更多推荐
所有评论(0)