涉及到的库
QSqlDatabase 数据库连接管理
负责管理应用程序与物理数据库之间的连接实例;
选择底层驱动:通过
QSqlDatabase::addDatabase("QSQLITE") 指定使用 SQLite 引擎。配置连接参数:通过
setDatabaseName() 设置本地数据库文件路径(或 :memory: 内存模式)。开启/关闭连接:提供
open() 和 close() 方法。事务控制:提供
transaction()(开启事务)、commit()(提交)、rollback()(回滚)接口,用于提升批量写入性能和保障原子性。
QSqlQuery 执行sql语句 和结果集游标
用于编写、执行 SQL 命令,并遍历执行结果。
执行原生 SQL:直接调用
exec("CREATE TABLE ...")。预编译与参数化防注入:通过
prepare() 配合 bindValue() 绑定占位符(如 :name 或 ?),避免 SQL 注入风险。遍历查询结果:通过
next() 向后移动游标读取下一行数据,并用 value("column_name") 提取具体字段的值。
QSqlError 数据库错误信息的包装
封装数据库层和 Qt 驱动层产生的报错信息
当
db.open() 或 query.exec() 返回 false 时,通过 db.lastError() 或 query.lastError() 获取该对象。调用
.text()、.databaseText() 或 .type() 提取详细的错误描述(如语法错误、磁盘锁住、字段不存在等),用于排查故障。
简单示例
需要在CMakeLists.txt中引入sql组件并链接:
find_package(Qt6 REQUIRED COMPONENTS Core Sql)
target_link_libraries(project_name PRIVATE
Qt6::Core
Qt6::Sql
)
初始化并建立数据库连接
bool initDatabase() {
QSqlDatabase db;
if (QSqlDatabase::contains(QSqlDatabase::defaultConnection)) {
db = QSqlDatabase::database(QSqlDatabase::defaultConnection);
if (db.isOpen()) {
return true;
}
} else {
db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("app_data.db");
}
if (!db.open()) {
qWarning() << "无法打开数据库:" << db.lastError().text();
return false;
}
return true;
}
QSqlDatabase::addDatabase() 实际上有两个参数,完整的函数声明是:
QSqlDatabase QSqlDatabase::addDatabase(const QString &type,
const QString &connectionName = QLatin1String(defaultConnection));
上面的initDatabase函数只传递了"QSQLITE",没有第二个参数connectionName时,QT会自动注册为默认连接QSqlDatabase::defaultConnection,其实就是个特殊字符串qt_sql_default_connection;连接会自动缓存在QT的全局静态映射表里,直到程序退出或主动销毁连接;
创建数据库表
bool createTable() {
QSqlQuery query;
QString sql = R"(
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
age INTEGER
)
)";
if (!query.exec(sql)) {
qWarning() << "建表失败:" << query.lastError().text();
return false;
}
return true;
}
这里的QSqlQuery同样有一个带默认值的参数:
QSqlQuery(QSqlDatabase db);
QSqlQuery(const QString &query = QString(), QSqlDatabase db = QSqlDatabase());
无参构造 QSqlQuery query; 会使用 Qt 的默认数据库连接;如果默认连接不存在,则这个 query 实际不可用,exec() 会失败。
CRUD
// 3. 插入数据(使用预编译与参数绑定,防止 SQL 注入)
bool insertUser(const QString &name, int age) {
QSqlQuery query;
query.prepare("INSERT INTO users (name, age) VALUES (:name, :age)");
query.bindValue(":name", name);
query.bindValue(":age", age);
if (!query.exec()) {
qWarning() << "插入数据失败:" << query.lastError().text();
return false;
}
return true;
}
// 4. 查询数据
void queryUsers() {
QSqlQuery query("SELECT id, name, age FROM users");
while (query.next()) {
int id = query.value("id").toInt();
QString name = query.value("name").toString();
int age = query.value("age").toInt();
qDebug() << "ID:" << id << "| 姓名:" << name << "| 年龄:" << age;
}
}
// 5. 更新与删除
bool updateUser(int id, int newAge) {
QSqlQuery query;
query.prepare("UPDATE users SET age = :age WHERE id = :id");
query.bindValue(":age", newAge);
query.bindValue(":id", id);
return query.exec();
}
bool deleteUser(int id) {
QSqlQuery query;
query.prepare("DELETE FROM users WHERE id = :id");
query.bindValue(":id", id);
return query.exec();
}
需要连接多个数据库
如果要连接多个数据库,如一个本地Sqlite,一个远程Mysql时,就不能依赖QT的默认连接,需要显示命名:
// 1. 创建两个命名连接
QSqlDatabase localDb = QSqlDatabase::addDatabase("QSQLITE", "local_conn");
localDb.setDatabaseName("local.db");
localDb.open();
QSqlDatabase remoteDb = QSqlDatabase::addDatabase("QMYSQL", "remote_conn");
remoteDb.setHostName("192.168.1.100");
// ... 设置并打开远程连接
// 2. 指定给 QSqlQuery 使用
QSqlQuery query1(localDb); // 指向本地数据库
query1.exec("SELECT * FROM local_table");
// 或者通过名字查找已存在的连接传进去:
QSqlQuery query2(QSqlDatabase::database("remote_conn")); // 指向远程数据库
query2.exec("SELECT * FROM remote_table");
一些注意事项
因为 Qt 在后台用全局池管理连接,如果作用域管理不当,很容易触发警告:
QSqlDatabasePrivate::removeDatabase: connection 'xxx' is still in use, all queries will cease to work.
原因:
如果在同一个函数内,QSqlDatabase 和 QSqlQuery 混在一起,可能导致 QSqlQuery 还没析构,连接就尝试关闭或移除。
规范写法:
让 QSqlQuery 尽量保持较小的局部生命周期,例如在函数内部创建 QSqlQuery query;,执行完随函数返回立即析构,不要把 QSqlQuery 存为长期的成员变量,这样最安全。
QT连接Sqlite数据库
本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
评论交流
欢迎留下你的想法