
示例代码:
cpp
QSqlDatabase db = QSqlDatabase::addDatabase("QSSLITE");
db.setDatabaseName("test.db");
db.open();
Qt 提供了一个强大的 SQL 模块,可以方便地连接和操作多种数据库。本文将介绍 Qt 中数据库操作的基本流程,并以 SQLite 为例演示增删改查(CRUD)操作,同时展示如何结合模型视图快速展示数据。
1. Qt SQL 模块概述
Qt SQL 模块支持多种主流数据库,包括:
-
SQLite(默认支持,无需额外配置)
-
MySQL / MariaDB
-
PostgreSQL
-
Oracle(通过 OCI)
-
ODBC(可用于连接 SQL Server 等)
-
以及其他通过插件支持的数据库
使用该模块时,需要在项目文件(.pro)中添加:
cpp
QT += sql
并在源代码中包含必要的头文件:
cpp
#include <QtSql>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include <QSqlTableModel>
#include <QTableView>
2. 建立数据库连接
数据库连接通过 QSqlDatabase 类管理。以下代码创建一个 SQLite 内存数据库,并打开连接:
cpp
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); // 使用 SQLite 驱动
db.setDatabaseName(":memory:"); // 内存数据库,也可以指定文件路径如 "test.db"
if (!db.open()) {
qDebug() << "数据库打开失败:" << db.lastError().text();
return;
}
qDebug() << "数据库连接成功!";
对于 MySQL 等数据库,还需要设置用户名、密码、主机名等:
cpp
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
db.setHostName("localhost");
db.setDatabaseName("mydb");
db.setUserName("root");
db.setPassword("password");
- 使用QSqlDatabase::contains()检查连接是否已存在,避免重复创建。
3. 执行 SQL 语句:QSqlQuery
QSqlQuery 用于执行任意 SQL 语句,并处理结果集。下面演示创建表、插入、查询、更新和删除操作。
3.1 创建表
cpp
QSqlQuery query;
bool success = query.exec(
"CREATE TABLE person ("
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
"name TEXT NOT NULL, "
"age INTEGER)"
);
if (!success) {
qDebug() << "创建表失败:" << query.lastError().text();
} else {
qDebug() << "创建表成功";
}
3.2 插入数据
插入数据可以使用 exec() 直接执行 SQL,也可以使用预处理语句(prepare + bind)防止 SQL 注入。
cpp
// 方式1:直接拼接字符串(不推荐,存在注入风险)
query.exec("INSERT INTO person (name, age) VALUES ('张三', 25)");
// 方式2:预处理语句(推荐)
query.prepare("INSERT INTO person (name, age) VALUES (:name, :age)");
query.bindValue(":name", "李四");
query.bindValue(":age", 30);
if (!query.exec()) {
qDebug() << "插入失败:" << query.lastError().text();
} else {
qDebug() << "插入成功";
}
3.3 查询数据
执行 SELECT 语句后,使用 next() 遍历结果集。
cpp
query.exec("SELECT id, name, age FROM person");
while (query.next()) {
int id = query.value(0).toInt();
QString name = query.value("name").toString(); // 可用列名或索引
int age = query.value(2).toInt();
qDebug() << id << name << age;
}
3.4 更新数据
cpp
query.prepare("UPDATE person SET age = :age WHERE name = :name");
query.bindValue(":age", 26);
query.bindValue(":name", "张三");
if (!query.exec()) {
qDebug() << "更新失败:" << query.lastError().text();
}
3.5 删除数据
cpp
query.prepare("DELETE FROM person WHERE name = :name");
query.bindValue(":name", "李四");
if (!query.exec()) {
qDebug() << "删除失败:" << query.lastError().text();
}
4. 使用模型视图简化开发
对于需要展示或编辑数据的场景,可以使用 QSqlTableModel 结合 QTableView,几行代码即可实现数据表格的显示和编辑。
cpp
// 创建模型并绑定到数据库表
QSqlTableModel *model = new QSqlTableModel;
model->setTable("person");
model->setEditStrategy(QSqlTableModel::OnManualSubmit); // 手动提交修改
model->select(); // 加载数据
// 设置表头
model->setHeaderData(0, Qt::Horizontal, "ID");
model->setHeaderData(1, Qt::Horizontal, "姓名");
model->setHeaderData(2, Qt::Horizontal, "年龄");
// 创建视图
QTableView *view = new QTableView;
view->setModel(model);
view->resizeColumnsToContents();
view->show();
通过模型视图,用户可以直接在表格中修改数据,然后调用 model->submitAll() 提交修改,或 model->revertAll() 撤销。
5. 事务处理
对于需要保证原子性的操作,可以使用事务:
cpp
if (db.transaction()) {
QSqlQuery query;
if (query.exec("INSERT ...") && query.exec("UPDATE ...")) {
db.commit();
qDebug() << "事务提交成功";
} else {
db.rollback();
qDebug() << "事务回滚:" << query.lastError().text();
}
} else {
qDebug() << "启动事务失败";
}
6. 完整示例代码
以下是一个完整的控制台程序,演示了 SQLite 内存数据库的增删改查操作:
cpp
#include <QCoreApplication>
#include <QtSql>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// 1. 连接数据库
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName(":memory:");
if (!db.open()) {
qDebug() << "数据库打开失败:" << db.lastError().text();
return -1;
}
// 2. 创建表
QSqlQuery query;
if (!query.exec("CREATE TABLE person (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER)")) {
qDebug() << "建表失败:" << query.lastError().text();
return -1;
}
// 3. 插入数据
query.prepare("INSERT INTO person (name, age) VALUES (?, ?)");
query.addBindValue("张三");
query.addBindValue(25);
if (!query.exec()) qDebug() << "插入失败:" << query.lastError().text();
query.bindValue(0, "李四");
query.bindValue(1, 30);
if (!query.exec()) qDebug() << "插入失败:" << query.lastError().text();
// 4. 查询数据
qDebug() << "查询所有记录:";
query.exec("SELECT * FROM person");
while (query.next()) {
qDebug() << query.value(0).toInt() << query.value(1).toString() << query.value(2).toInt();
}
// 5. 更新数据
query.prepare("UPDATE person SET age = :age WHERE name = :name");
query.bindValue(":age", 26);
query.bindValue(":name", "张三");
if (!query.exec()) qDebug() << "更新失败:" << query.lastError().text();
// 6. 删除数据
query.prepare("DELETE FROM person WHERE name = :name");
query.bindValue(":name", "李四");
if (!query.exec()) qDebug() << "删除失败:" << query.lastError().text();
// 7. 再次查询验证
qDebug() << "操作后剩余记录:";
query.exec("SELECT * FROM person");
while (query.next()) {
qDebug() << query.value(0).toInt() << query.value(1).toString() << query.value(2).toInt();
}
db.close();
return 0;
}
7. 常见问题与注意事项
-
驱动加载:部分数据库(如 MySQL)需要编译相应的驱动插件,确保 Qt 安装时包含该驱动。
-
错误处理 :每次执行 SQL 后都应检查
lastError(),尤其在生产代码中。 -
线程安全 :
QSqlDatabase实例不可跨线程使用,每个线程需建立自己的连接。 -
模型视图 :
QSqlTableModel默认使用OnManualSubmit策略,如需自动提交可改为OnRowChange或OnFieldChange。 -
性能 :批量操作时使用
QSqlQuery::prepare()和addBindValue()可以有效提升性能并避免 SQL 注入。
8. 总结
Qt SQL 模块提供了一套完整的数据库操作接口,从底层 QSqlQuery 到高层模型视图,开发者可以根据需求灵活选择。对于小型应用,SQLite 搭配 QSqlTableModel 可以快速实现数据管理功能;对于大型项目,Qt 也能无缝对接 MySQL、PostgreSQL 等企业级数据库。掌握这些基础操作,即可在 Qt 项目中游刃有余地处理数据持久化问题。