Qt Sqlite3事务的正确使用方法(Visual Studio开发场景)
问题
使用Visual Studio 2022开发Qt应用时,调用Sqlite3事务出现异常:事务执行过程中,即便某条SQL语句执行失败,之前的操作仍会被提交到数据库,无法触发整体回滚;但在Navicat中执行相同逻辑的SQL事务时,所有操作会正常回滚。请问Qt中正确使用Sqlite3事务的方法是什么?
问题代码片段
#include <QSqlDatabase> #include <QSqlQuery> #include <QDebug> int main(int argc, char* argv[]) { QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName("dst.db"); if (!db.open()) { //can't open db return 1; } QSqlQuery* query1 = new QSqlQuery(db); db.transaction(); if (!query1->exec("create table test(u,p);")) { qDebug() << "create table [fail]\n"; } if (!query1->exec("INSERT INTO test(u,p) VALUES ('tangying','332233');")) { qDebug() << "insert data [fail]\n"; } //the result of this query should be failed or the result or committing should be failed // because the table `tes` not exist // the correct result should be that all work should rollback //but the previous query execute successfully in the database if (!query1->exec("INSERT INTO tes(u,p) VALUES ('tangying','332233');")) { qDebug() << "insert data2 [fail]\n"; } if (!db.commit()) { qDebug() << "commit [fail]"; } return 0; }
Navicat测试情况
执行的SQL代码:
BEGIN TRANSACTION; create table test(u,p); INSERT INTO test(u,p) VALUES ('tangying','332233'); INSERT INTO tes(u,p) VALUES ('tangying','332233'); COMMIT;
执行结果:
BEGIN TRANSACTION; OK create table test(u,p); OK INSERT INTO test(u,p) VALUES ('tangying','332233'); Affected rows:1 INSERT INTO tes(u,p) VALUES ('tangying','332233'); No such table
刷新表列表后,所有操作均未执行,符合事务回滚预期。
解决方案
问题核心在于你的代码未在SQL执行失败时主动触发回滚:Qt不会自动在单条SQL执行失败时终止事务,若继续执行后续逻辑并最终调用commit(),之前成功的操作会被提交。正确的做法是在任意一步失败时立即回滚事务并终止流程。
正确事务处理逻辑
- 启动事务时检查返回值,确保事务成功开启
- 每一步SQL执行失败时,立即调用
db.rollback()回滚所有操作,停止后续流程 - 所有SQL执行成功后,再调用
db.commit()提交事务 - 使用局部
QSqlQuery对象,避免动态分配导致的内存泄漏
修改后的代码示例
#include <QSqlDatabase> #include <QSqlQuery> #include <QDebug> int main(int argc, char* argv[]) { QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName("dst.db"); if (!db.open()) { qDebug() << "无法打开数据库"; return 1; } QSqlQuery query(db); // 局部对象,自动管理内存 // 启动事务并检查结果 if (!db.transaction()) { qDebug() << "启动事务失败:" << db.lastError().text(); db.close(); return 1; } // 执行建表语句 if (!query.exec("create table test(u,p);")) { qDebug() << "create table [fail]:" << query.lastError().text(); db.rollback(); // 失败则回滚 db.close(); return 1; } // 执行插入语句 if (!query.exec("INSERT INTO test(u,p) VALUES ('tangying','332233');")) { qDebug() << "insert data [fail]:" << query.lastError().text(); db.rollback(); // 失败则回滚 db.close(); return 1; } // 执行错误的插入语句(表名错误) if (!query.exec("INSERT INTO tes(u,p) VALUES ('tangying','332233');")) { qDebug() << "insert data2 [fail]:" << query.lastError().text(); db.rollback(); // 失败则回滚 db.close(); return 1; } // 所有操作成功,提交事务 if (db.commit()) { qDebug() << "事务提交成功"; } else { qDebug() << "commit [fail]:" << db.lastError().text(); db.rollback(); // 提交失败也需回滚 } db.close(); return 0; }
关键要点说明
- 主动回滚:任何一步SQL执行失败后必须立即调用
db.rollback(),否则之前的操作会在commit()时被提交。 - 事务启动校验:
db.transaction()可能启动失败,必须检查返回值。 - 提交失败处理:即使所有SQL执行成功,
commit()仍可能因数据库异常失败,此时也需要回滚。 - 资源管理:避免使用
new QSqlQuery,改用局部对象自动释放内存。
内容的提问来源于stack exchange,提问作者Andrew
相关产品推荐
相关产品推荐

