摘要:
这一篇Qt博文主要介绍在Qt开发中针对数据库相关开发时可以用到或参考的一些数据库类,例如显示数据库的数据通常涉及到几个关键组件,包括数据库连接、查询执行以及用户界面元素的更新等等,这些类的作用是什么,大致应该怎么用,类的常用类方法及相关需要注意的事项等等,更多更加细致的需根据类名查找翻阅官方帮助文档。
QT提供的与数据库操作相关的类有以下几个:
- QSqlDatabase:这个类用于处理与数据库的连接。
- QSqlError:这个类提供了在数据库连接或查询过程中发生错误时的关键信息。
- QSqlIndex:这个类用于表示数据库中的索引。
- QSqlQuery:这个类用于执行SQL语句并获取结果。
- QSqlQueryModel:这个类是一个基于SQL查询的模型,用于与视图(如
QTableView)结合使用。 - QSqlRecord:这个类表示从数据库查询结果中检索到的一条记录。
- QSqlField:这个类表示数据库表或视图中单个列的特征。
- QSqlTableModel:这个类是一个基于数据库表的模型,为单个数据库表提供可编辑的数据模型。
- QSqlDriverPlugin:通过子类化这个基类,可以创建自己的SQL驱动插件。
- QSqlRelationalTableModel:这个类为单个数据库表提供了一个可编辑的数据模型,它支持外键和关系数据的展示和编辑。
开发环境:Qt5.14.1,Qt Creator 4.11.1
关键词: Qt,数据库操作,sql,总结,QSqlDatabase,QSqlError,QSqlIndex,QSqlQuery,QSqlQueryModel,QSqlRecord,QSqlField,QSqlTableModel,QSqlDriverPlugin,QSqlRelationalTableModel
声明:
本文作者原创,转载请附上文章出处与本文链接。
正文:
QSqlDatabase
这个类用于处理与数据库的连接。它提供了一个接口来访问数据库,并通过调用静态函数addDatabase()来创建连接。一个QSqlDatabase的实例代表一个数据库连接,该连接通过受支持的数据库驱动程序提供对数据库的访问。
常用成员函数:
addDatabase(const QString &type, const QString &connectionName = QString()):用于添加一个新的数据库连接。type参数指定数据库类型(如 "QMYSQL", "QPSQL", "QSQLITE" 等),connectionName是连接的名称。database(const QString &connectionName = QString()):返回指定名称的数据库连接。如果没有指定名称,则返回默认的数据库连接。removeDatabase(const QString &connectionName):移除指定的数据库连接。isOpen() const:检查数据库连接是否打开。open():打开数据库连接。close():关闭数据库连接。lastError():返回最后一次数据库操作的错误信息。exec(const QString &query):执行 SQL 查询,并返回一个QSqlQuery对象,用于处理查询结果。transaction():开始一个新的事务。commit():提交当前事务。rollback():回滚当前事务。
使用例子:
首先,确保你的 Qt 项目包含了 SQL 模块,可以通过项目文件(.pro)来添加模块:
// .pro文件
QT += sql
然后在main.cpp即可:
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// 添加数据库连接
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("path/to/your/database.db"); // 替换为你的数据库文件路径
// 打开数据库连接
if (!db.open()) {
qDebug() << "Error: Could not open database";
return -1;
}
// 执行 SQL 语句,创建表
QSqlQuery query;
if (!query.exec("CREATE TABLE person (id INT PRIMARY KEY, name VARCHAR(20))")) {
qDebug() << "Error: Could not create table";
return -1;
}
// 执行 SQL 语句,为刚刚创建的表插入数据
if (!query.exec("INSERT INTO person (id, name) VALUES (1, 'Alice')")) {
qDebug() << "Error: Could not insert data";
return -1;
}
// 执行查询并打印输出结果
query.exec("SELECT * FROM person");
while (query.next()) {
int id = query.value(0).toInt();
QString name = query.value(1).toString();
qDebug() << "ID:" << id << "Name:" << name;
}
// 关闭数据库连接
db.close();
return a.exec();
}
QSqlError
这个类提供了在数据库连接或查询过程中发生错误时的关键信息。它包含如错误消息、原生错误代码等属性,帮助开发者识别和处理数据库操作中的错误。
常用成员函数:
text() const:返回描述错误的文本信息。这通常是一个人类可读的字符串,描述了错误的原因。nativeErrorCode() const:返回数据库特定的错误代码。这个代码通常对于特定的数据库系统是有意义的,它可以帮助你更准确地诊断问题。type() const:返回错误的类型。这通常是一个枚举值,表示错误的性质(例如,连接错误、查询错误等)。isValid() const:返回一个布尔值,指示是否存在有效的错误信息。如果QSqlError对象不包含错误(即没有错误发生),这个函数将返回false。
使用例子:
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// 添加数据库连接(这里以 SQLite 为例)
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("path/to/your/database.db");
if (!db.open()) {
// 处理数据库连接错误
QSqlError error = db.lastError();
qDebug() << "Database connection error:" << error.text();
return -1;
}
// 执行 SQL 查询
QSqlQuery query;
query.exec("SELECT * FROM non_existent_table"); // 假设这个表不存在
if (query.lastError().isValid()) {
// 处理查询错误
QSqlError error = query.lastError();
qDebug() << "Query error:" << error.text();
qDebug() << "Native error code:" << error.nativeErrorCode();
qDebug() << "Error type:" << error.type();
} else {
// 处理查询结果(在这个例子中,由于表不存在,不会执行到这里)
while (query.next()) {
// ... 处理每一行数据 ...
}
}
// 关闭数据库连接
db.close();
return a.exec();
}
QSqlIndex
这个类用于表示数据库中的索引。它通常用于优化查询性能,通过指定一个或多个字段来创建索引。
常用成员函数:
name() const:返回索引的名称。setName(const QString &name):将索引的名称设置为name。append(const QSqlField &field, bool desc = false):向索引中添加一个字段,并指定是否按降序排序。setDescending(int i, bool desc):设置索引中指定位置的字段是否按降序排序。clear():清除索引中的所有字段。
使用例子:
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlIndex>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// 添加数据库连接(这里以 SQLite 为例)
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("path/to/your/database.db");
if (!db.open()) {
// 处理数据库连接错误
qDebug() << "Error connecting to database";
return -1;
}
// 假设我们有一个名为 "employees" 的表,并且我们想按 "lastName" 字段降序排序
QSqlQuery query;
QSqlIndex index("lastName", true); // 创建一个降序索引
// 执行查询,使用 QSqlIndex 来指定排序条件,用prepare缓冲
query.prepare("SELECT * FROM employees ORDER BY :sortColumn");
query.bindValue(":sortColumn", index);
if (!query.exec()) {
// 处理查询错误
qDebug() << "Query error:" << query.lastError().text();
return -1;
}
// 处理查询结果
while (query.next()) {
QString lastName = query.value(index.fieldName(0)).toString();
qDebug() << "Last Name:" << lastName;
// ... 处理其他字段 ...
}
// 关闭数据库连接
db.close();
return a.exec();
}
QSqlQuery
这个类用于执行SQL语句并获取结果。它提供了执行查询、插入、更新和删除等操作的方法,并可以处理查询结果。
常用成员函数:
exec():执行 SQL 语句。对于非查询语句(如 INSERT、UPDATE、DELETE),此函数返回是否成功执行。prepare(const QString &query):准备 SQL 语句以供执行。这允许你使用占位符(如:placeholder),并使用bindValue()函数来绑定具体的值。bindValue(const QString &placeholder, const QVariant &val, QSql::ParamType type = QSql::In):绑定一个值到 SQL 语句中的占位符。这增加了安全性,并避免了 SQL 注入攻击。next():将查询结果的位置前进到下一行。在查询结果集上迭代时常用。seek(int row):将查询结果的位置移动到指定行。value(int index):返回当前行中指定列的值。列索引从 0 开始。record():返回当前行的QSqlRecord对象,它包含行中所有字段的信息。lastError():返回最近一次数据库操作的错误信息。如果操作成功,则返回的QSqlError对象将不包含有效的错误信息。isSelect():检查查询是否是 SELECT 语句。
使用例子:
#include <QCoreApplication>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// 添加数据库连接
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("path/to/your/database.db");
if (!db.open()) {
// 无法打开数据库,处理错误
qDebug() << "无法连接到数据库: " << db.lastError().text();
return -1;
}
// 创建表
QSqlQuery query;
query.exec("CREATE TABLE employee ("
"id INTEGER PRIMARY KEY,"
"name TEXT NOT NULL,"
"age INTEGER)");
// 插入数据
query.exec("INSERT INTO employee (name, age) VALUES ('Alice', 30)");
query.exec("INSERT INTO employee (name, age) VALUES ('Bob', 25)");
query.exec("INSERT INTO employee (name, age) VALUES ('Charlie', 35)");
// 查询数据
query.exec("SELECT * FROM employee");
while (query.next()) {
int id = query.value(0).toInt();
QString name = query.value(1).toString();
int age = query.value(2).toInt();
qDebug() << "ID:" << id << "Name:" << name << "Age:" << age;
}
// 关闭数据库连接
db.close();
return a.exec();
}
QSqlQueryModel
这个类是一个基于SQL查询的模型,QSqlQueryModel是执行SQL语句和遍历结果集的高级接口,它建立在较低级别的QSqlQuery之上,用于与视图(如QTableView)结合使用。它将SQL查询的结果封装成模型,方便在视图中展示和操作数据。
常用成员函数:
setQuery(const QString &query):设置要执行的 SQL 查询。rowCount(const QModelIndex &parent = QModelIndex()) const:返回模型中的行数。columnCount(const QModelIndex &parent = QModelIndex()) const:返回模型中的列数。data(const QModelIndex &index, int role = Qt::DisplayRole) const:返回给定索引和角色的数据。index(int row, int column, const QModelIndex &parent = QModelIndex()) const:返回对应于给定行和列的模型索引。record(int row) const:返回包含有关当前查询字段信息的记录,即给定行的QSqlRecord。lastError() const:返回最后一次查询的错误信息。
使用例子:
当你创建 QSqlQueryModel 的实例时,它会在内部使用当前默认的数据库连接(通过 QSqlDatabase::database() 获取)来执行查询,如果你的程序有多个数据库连接,并且你想要 QSqlQueryModel 使用特定的连接,例如db2,那么阔以通过 QSqlDatabase::setDatabaseDefault(db2) 将 db2 设置为默认数据库连接,或者可以使用 QSqlQuery 的构造函数来指定连接名称。
#include <QApplication>
#include <QSqlDatabase>
#include <QSqlQueryModel>
#include <QTableView>
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// 添加数据库连接(这里以SQLite为例)
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("path/to/your/database.db");
if (!db.open()) {
qDebug() << "无法连接到数据库: " << db.lastError().text();
return -1;
}
// 创建 QSqlQueryModel 实例
QSqlQueryModel *model = new QSqlQueryModel();
// 设置查询语句
model->setQuery("SELECT * FROM employee");
// 检查查询是否成功
if (model->lastError().isValid()) {
qDebug() << "查询错误: " << model->lastError().text();
return -1;
}
// 创建 QTableView 实例并设置模型
QTableView *view = new QTableView();
view->setModel(model);
view->show();
// 可选:设置表头标签
model->setHeaderData(0, Qt::Horizontal, QObject::tr("ID"));
model->setHeaderData(1, Qt::Horizontal, QObject::tr("Name"));
model->setHeaderData(2, Qt::Horizontal, QObject::tr("Age"));
// 关闭数据库连接
db.close();
return a.exec();
}
QSqlRecord
这个类表示从数据库查询结果中检索到的一条记录。它包含记录中的字段及其值,封装了数据库记录的功能和特征,通常是数据库中表或视图中的一行。通过QSqlRecord,可以访问和修改数据库记录中的字段。
常用成员函数:
value(int i):返回指定索引i的字段的值。value(const QString &name):返回指定名称name的字段的值。fieldName(int i):返回指定索引i的字段的名称。count():返回记录中的字段数量。isEmpty():如果记录为空,则返回true。clear():清除记录中的所有字段。contains(const QString &name):如果记录包含指定名称name的字段,则返回true。setValue(int index, const QVariant &val):将位置索引处的字段值设置为val。如果该字段不存在,则不发生任何操作。setValue(const QString &name, const QVariant &val):将名为name的字段的值设置为val。
使用例子:
#include <QApplication>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// 添加数据库连接(这里以SQLite为例)
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("path/to/your/database.db");
if (!db.open()) {
qDebug() << "无法连接到数据库: " << db.lastError().text();
return -1;
}
// 执行查询
QSqlQuery query;
if (!query.exec("SELECT * FROM employee")) {
qDebug() << "查询失败: " << query.lastError().text();
return -1;
}
// 遍历查询结果
while (query.next()) {
// 获取当前行的 QSqlRecord
const QSqlRecord &record = query.record();
// 访问记录中的字段
for (int i = 0; i < record.count(); ++i) {
QString fieldName = record.fieldName(i);
QVariant fieldValue = record.value(i);
qDebug() << fieldName << ": " << fieldValue;
}
}
// 关闭数据库连接
db.close();
return a.exec();
}
QSqlField
这个类表示数据库表或视图中单个列的特征,QSqlField类操作SQL数据库表和视图中的字段。通常通过QSqlRecord或QSqlQueryModel等类间接访问。
常用成员函数:
name() const:返回字段的名称。setName(const QString &name):将字段的名称设置为name。value() const:返回字段的值。setValue(const QVariant &value)设置字段的值,实际不改变数据库内值。type() const:返回字段的数据类型。setType(QVariant::Type type):设置字段的变量类型为type。isNull() const:如果字段的值是 NULL,则返回true。clear():清除字段的值。
使用例子:
#include <QApplication>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QSqlField>
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// 添加数据库连接(这里以SQLite为例)
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("path/to/your/database.db");
if (!db.open()) {
qDebug() << "无法连接到数据库: " << db.lastError().text();
return -1;
}
// 执行查询
QSqlQuery query;
if (!query.exec("SELECT id, name FROM employee")) {
qDebug() << "查询失败: " << query.lastError().text();
return -1;
}
// 遍历查询结果
while (query.next()) {
// 获取当前行的 QSqlRecord
const QSqlRecord &record = query.record();
// 访问记录中的特定字段
QSqlField idField = record.field("id");
QSqlField nameField = record.field("name");
// 打印字段信息
qDebug() << "ID:" << idField.value();
qDebug() << "Name:" << nameField.value().toString();
// 修改字段值
// 注意:在实际应用中,直接修改查询结果中的字段值可能不是一个好主意,
// 因为这不会改变数据库中的实际数据。这里只是为了演示如何设置字段值。
nameField.setValue("Modified Name");
qDebug() << "Modified Name:" << nameField.value().toString();
}
// 关闭数据库连接
db.close();
return a.exec();
}
QSqlTableModel
这个类是一个基于数据库表的模型,为单个数据库表提供可编辑的数据模型。QSqlTableModel是一个高级接口,用于从单个表中读写数据库记录, 它建立在较低级别的QSqlQuery之上,可用于向QTableView等视图类提供数据。
常用成员函数:
setTable(const QString &tableName):设置要查询的数据库表名。tableName() const:返回当前选定表的名称。setEditStrategy(QSqlTableModel::EditStrategy strategy):将数据库中编辑值的策略设置为strategy。select():使用通过setTable()设置的表中的数据填充模型,使用指定的筛选和排序条件。setFilter(const QString &filter):设置筛选条件,用于限制查询结果。setSort(int column, Qt::SortOrder order):将列的排序顺序设置为order。submitAll():提交所有挂起的更改revertAll():重置所有缓存操作。index(int row, int column, const QModelIndex &parent = QModelIndex()) const:返回模型中指定行和列的 QModelIndex。data(const QModelIndex &index, int role = Qt::DisplayRole) const:返回模型中指定索引的数据,可以根据不同的角色(如显示、编辑等)返回不同的数据。setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole):设置模型中指定索引的数据。
使用例子:
#include <QApplication>
#include <QSqlDatabase>
#include <QSqlTableModel>
#include <QSqlRelationalTableModel>
#include <QTableView>
#include <QHeaderView>
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
// 设置数据库连接(这里以SQLite为例)
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("path/to/your/database.db");
if (!db.open()) {
qDebug() << "Failed to open database";
return -1;
}
// 创建 QSqlTableModel 实例
QSqlTableModel *model = new QSqlTableModel();
model->setTable("students"); // 设置要查询的表名
model->setEditStrategy(QSqlTableModel::OnFieldChange); // 设置编辑策略,这里为字段更改时提交
// 设置过滤器,只显示年龄大于20的学生
model->setFilter("age > 20");
// 设置排序,按年龄升序排序
model->setSort(model->fieldIndex("age"), Qt::AscendingOrder);
model->select(); // 执行查询并填充模型
// 显示数据
QTableView *view = new QTableView();
view->setModel(model);
view->horizontalHeader()->setSortIndicator(model->fieldIndex("age"), Qt::AscendingOrder); // 设置表头排序指示器
view->show();
// 假设用户编辑了数据,我们需要提交这些更改到数据库
if (model->submitAll()) {
qDebug() << "Changes submitted successfully";
} else {
qDebug() << "Failed to submit changes";
}
// 关闭数据库连接
db.close();
return app.exec();
}
QSqlDriverPlugin
这个类为自定义的QSqlDriver插件提供了一个抽象基类。通过子类化这个基类,可以创建自己的SQL驱动插件,这些插件可以通过Qt动态加载,这些插件为Qt提供了扩展数据库驱动支持的能力。进阶能力,大部分用不到,使用 Qt 已经提供的驱动程序即可。
使用例子:
#include <QSqlDriverPlugin>
#include <QSqlDriver>
#include <QSqlError>
#include <QString>
class MyCustomSqlDriverPlugin : public QSqlDriverPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QSqlDriverFactoryInterface" FILE "mydriver.json")
public:
MyCustomSqlDriverPlugin() = default;
QSqlDriver *create(const QString &name) override
{
if (name == "MYCUSTOMDB") {
MyCustomSqlDriver *driver = new MyCustomSqlDriver();
return driver;
}
return nullptr;
}
};
class MyCustomSqlDriver : public QSqlDriver
{
Q_OBJECT
public:
MyCustomSqlDriver() : QSqlDriver("MYCUSTOMDB") {}
bool open(const QString &db, const QString &user, const QString &password,
const QString &host, int port, const QString &connOpts) override
{
// 实现打开数据库连接的逻辑
// ...
return true; // 假设成功
}
// 实现其他必要的方法,如 close(), exec(), isOpen() 等
// ...
};
在这个例子中,MyCustomSqlDriverPlugin 类继承自 QSqlDriverPlugin,并重写了 create 方法。这个方法根据提供的名称来创建并返回一个新的 QSqlDriver 实例。在这个例子中,如果名称是 "MYCUSTOMDB",则创建一个 MyCustomSqlDriver 的实例。
MyCustomSqlDriver 类是 QSqlDriver 的子类,它必须实现打开数据库连接、执行 SQL 语句、关闭连接等必要的方法。在这个简化的例子中,这些方法并没有实际的实现。
为了使用这个插件,你需要将其编译为一个动态链接库(.dll、.so 或 .dylib 文件),并根据你的操作系统和 Qt 的配置将其放置在正确的插件目录中。然后,Qt SQL 模块在尝试连接数据库时会自动加载和使用这个插件。
QSqlTableModel不直接支持外键。
如果要解析外键,请使用QSqlRelationalTableModel,QSqlRelationalDelegate。
QSqlRelationalTableModel
这个类为单个数据库表提供了一个可编辑的数据模型,它支持外键和关系数据的展示和编辑。QSqlTableModel和QSqlRelationalTableModel,它们没有太大的不同,唯一的就是后者在前者的基础之上添加了外键(或者叫外码)的支持。
具体来说,外键是约束定义从一个表(称为子表或引用表)到另一个表(称为父表或被引用表)的字段之间的关系,说简单点就是将两个相关的表建立一个桥梁,让它们关联起来。
常用成员函数:
setRelation(int column, const QSqlRelation &relation):在模型的列和另一个数据库表之间建立关系。这通常用于处理外键。主要是这个,其它成员函数以及显示数据方法和QSqlTableModel几乎无差。setTable(const QString &tableName):设置要查询的数据库表名。tableName() const:返回当前选定表的名称。setEditStrategy(QSqlTableModel::EditStrategy strategy):将数据库中编辑值的策略设置为strategy。select():使用通过setTable()设置的表中的数据填充模型,使用指定的筛选和排序条件。setFilter(const QString &filter):设置筛选条件,用于限制查询结果。setSort(int column, Qt::SortOrder order):将列的排序顺序设置为order。submitAll():提交所有挂起的更改revertAll():重置所有缓存操作。index(int row, int column, const QModelIndex &parent = QModelIndex()) const:返回模型中指定行和列的 QModelIndex。data(const QModelIndex &index, int role = Qt::DisplayRole) const:返回模型中指定索引的数据,可以根据不同的角色(如显示、编辑等)返回不同的数据。setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole):设置模型中指定索引的数据。
使用例子:
我们有两个数据库表:employees 和 departments。employees 表有一个字段 department_id,它是 departments 表中 id 字段的外键。
CREATE TABLE departments (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL
);
CREATE TABLE employees (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
department_id INTEGER,
FOREIGN KEY(department_id) REFERENCES departments(id)
);
使用 QSqlRelationalTableModel 来表示这两个表之间的关系,并通过QTableView显示员工及其所在部门的信息。
#include <QApplication>
#include <QTableView>
#include <QSqlDatabase>
#include <QSqlRelationalTableModel>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
// 初始化数据库连接
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("path/to/your/database.db");
if (!db.open()) {
qDebug() << "Error opening database:" << db.lastError();
return -1;
}
// 创建 QSqlRelationalTableModel 实例
QSqlRelationalTableModel *model = new QSqlRelationalTableModel;
model->setTable("employees"); // employees 表已经存在
model->setRelation(model->fieldIndex("department_id"), // department_id 是外键字段
QSqlRelation("departments", "id", "name")); // departments 表和字段已经存在
model->select(); // 查询数据
// 显示模型数据
QTableView *view = new QTableView;
view->setModel(model);
view->show();
// 关闭数据库连接
db.close();
return app.exec();
}