简介:本文深入解析Qt数据库操作中的事务机制,从基本概念到实际应用,结合代码示例探讨事务的ACID特性、实现方式及错误处理策略。
事务是数据库操作的核心机制,通过一组逻辑上相关的操作确保数据一致性。Qt作为跨平台C++框架,通过QSqlDatabase和QSqlQuery类提供了完整的事务支持。
QSqlDatabase::transaction()和rollback()实现这一特性。QSqlDriver::hasFeature(QSqlDriver::Transactions)检查驱动支持情况。Qt通过QSqlDatabase类封装了事务操作,核心API包括:
QSqlDatabase db = QSqlDatabase::database(); // 获取数据库连接db.transaction(); // 开启事务QSqlQuery query;query.exec("UPDATE accounts SET balance = balance - 100 WHERE id = 1");query.exec("UPDATE accounts SET balance = balance + 100 WHERE id = 2");if (/* 检查操作结果 */) {db.commit(); // 提交事务} else {db.rollback(); // 回滚事务}
Qt不支持真正的事务嵌套,但可通过保存点(Savepoints)模拟:
db.transaction();// 执行部分操作...QSqlQuery savepointQuery;savepointQuery.exec("SAVEPOINT my_savepoint");// 尝试风险操作...if (/* 失败 */) {savepointQuery.exec("ROLLBACK TO SAVEPOINT my_savepoint");} else {db.commit();}
检查驱动支持:
if (!db.driver()->hasFeature(QSqlDriver::Transactions)) {qWarning() << "Database does not support transactions!";return;}
统一错误处理:
bool executeTransaction(QSqlDatabase& db, const std::function<bool()>& operations) {if (!db.transaction()) {qWarning() << "Failed to start transaction:" << db.lastError().text();return false;}try {if (operations()) {if (!db.commit()) {qWarning() << "Commit failed:" << db.lastError().text();return false;}return true;} else {db.rollback();return false;}} catch (...) {db.rollback();throw;}}
Qt支持通过SQL语句设置隔离级别(需数据库驱动支持):
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; -- 最严格级别
常见级别对比:
| 级别 | 脏读 | 不可重复读 | 幻读 |
|———————|———|——————|———|
| READ UNCOMMITTED | ✓ | ✓ | ✓ |
| READ COMMITTED | ✗ | ✓ | ✓ |
| REPEATABLE READ | ✗ | ✗ | ✓ |
| SERIALIZABLE | ✗ | ✗ | ✗ |
query.exec("SET LOCK_TIMEOUT 5000"); // 5秒超时
对于跨数据库事务,Qt本身不提供直接支持,但可通过以下方案实现:
建议实现事务日志表:
CREATE TABLE transaction_logs (id INTEGER PRIMARY KEY,operation TEXT NOT NULL,status TEXT CHECK(status IN ('pending', 'committed', 'rolledback')),timestamp DATETIME DEFAULT CURRENT_TIMESTAMP);
transaction()症状:数据库连接池耗尽,其他操作阻塞
解决方案:
SET LOCK_TIMEOUT)不同数据库驱动的事务语法差异:
// SQLite特殊处理if (db.driverName() == "QSQLITE") {query.exec("BEGIN IMMEDIATE TRANSACTION"); // SQLite的特殊语法}
#include <QCoreApplication>#include <QSqlDatabase>#include <QSqlQuery>#include <QSqlError>#include <QDebug>class DatabaseTransaction {public:explicit DatabaseTransaction(QSqlDatabase& db) : m_db(db), m_committed(false) {if (!m_db.transaction()) {qWarning() << "Transaction start failed:" << m_db.lastError().text();}}~DatabaseTransaction() {if (!m_committed && m_db.isActive()) {m_db.rollback();qWarning() << "Automatic rollback due to destructor call";}}bool commit() {if (m_committed) {qWarning() << "Transaction already committed";return false;}if (m_db.commit()) {m_committed = true;return true;} else {qWarning() << "Commit failed:" << m_db.lastError().text();return false;}}private:QSqlDatabase& m_db;bool m_committed;};int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");db.setDatabaseName(":memory:");if (!db.open()) {qFatal("Failed to open database");}// 初始化表结构QSqlQuery query;query.exec("CREATE TABLE accounts (id INTEGER PRIMARY KEY, balance REAL)");query.exec("INSERT INTO accounts VALUES (1, 1000), (2, 1000)");// 事务操作示例{DatabaseTransaction trans(db);QSqlQuery update1;update1.prepare("UPDATE accounts SET balance = balance - ? WHERE id = ?");update1.addBindValue(100);update1.addBindValue(1);if (!update1.exec()) {qWarning() << "Update 1 failed:" << update1.lastError().text();return -1;}QSqlQuery update2;update2.prepare("UPDATE accounts SET balance = balance + ? WHERE id = ?");update2.addBindValue(100);update2.addBindValue(2);if (!update2.exec()) {qWarning() << "Update 2 failed:" << update2.lastError().text();return -1;}if (!trans.commit()) {qWarning() << "Transaction failed to commit";return -1;}}// 验证结果query.exec("SELECT * FROM accounts");while (query.next()) {qDebug() << "Account" << query.value(0).toInt()<< "Balance:" << query.value(1).toDouble();}return 0;}
通过系统掌握Qt的事务机制,开发者可以构建出更加健壮、可靠的数据持久层应用,有效避免数据不一致等严重问题。