C++如何使用数据库事务(Transaction)

事务未生效需先确认使用InnoDB引擎;C++中用MySQL Connector/C++应调用setAutoCommit(false)开启事务,执行SQL后commit()提交或rollback()回滚,并确保每个ResultSet读取完毕或关闭,且连接不跨线程共享。

c++如何使用数据库事务(transaction)

事务没生效?先确认你用的是支持事务的存储引擎

MySQL 默认的 MyISAM 引擎根本不支持事务,COMMITROLLBACK 会静默失败——你代码写得再标准也没用。必须用 InnoDBMEMORY(后者不持久,慎用)。建表时显式指定:

CREATE TABLE account (id INT, balance DECIMAL) ENGINE=InnoDB;

如果已有表,用 ALTER TABLE account ENGINE=InnoDB; 转换。PostgreSQL 和 SQLite 默认都支持事务,但 SQLite 的 WAL 模式下并发行为有差异,后面会提。

C++里怎么开启、提交和回滚事务?以 MySQL Connector/C++ 为例

别直接拼接 START TRANSACTION 字符串执行——这容易被连接池或自动重连机制打断。要用驱动提供的事务控制接口:

  • sql::Connection::setAutoCommit(false) 是起点,关闭自动提交后所有语句都在同一事务上下文中
  • 执行完 SQL(如 stmt->executeUpdate("UPDATE account SET balance = balance - 100 WHERE id = 1"))后,调用 conn->commit() 提交
  • 出错时必须显式调用 conn->rollback(),否则连接可能卡在未提交状态,后续操作被阻塞
  • 记得恢复 conn->setAutoCommit(true),否则下次获取连接时仍处于手动事务模式,极易引发诡异问题

事务里执行多条语句,为什么第二条就报错“Commands out of sync”?

这是 MySQL C++ 驱动常见陷阱:执行 SELECT 后没取完结果集,就紧接着执行 UPDATE,底层 socket 缓冲区混乱。解决方法只有两个:

  • 对每个 sql::Statementsql::PreparedStatement,执行查询后必须调用 res->next() 直到返回 false,或直接用 res->close()
  • 更稳妥的做法是:一个事务内,每个 executeQuery() 配套一个独立的 sql::ResultSet 对象,并在其作用域结束前完成读取或关闭
  • SQLite 的 sqlite3_exec() 没这个问题,但它的 BEGIN IMMEDIATE 会立即加锁,高并发下容易死锁

跨线程共享 connection 对象做事务安全吗?

完全不安全。C++ 数据库连接对象(如 sql::Connection*)不是线程安全的,即使加了互斥锁,事务状态(autocommit 开关、当前事务 ID)也只属于该连接实例。常见错误是:

立即学习“C++免费学习笔记(深入)”;

  • 线程 A 调用 setAutoCommit(false),线程 B 同时调用 executeUpdate() —— B 的语句可能意外进入 A 的事务,也可能被自动提交
  • 连接池返回的连接默认是 autocommit=true,你不能假设它“干净”,每次使用前必须显式设置
  • 真正安全的做法:每个线程独占一个连接,事务生命周期严格绑定在线程内;或者用 RAII 封装,构造时 setAutoCommit(false),析构时按需 commit()rollback()

事务的边界比看起来更脆弱——它依赖连接状态、驱动实现、甚至网络中间件是否透传 COMMIT 包。别省略任何一次 rollback(),也别信任连接池自动清理事务状态。

文章来自机圈观察员网,发布者:,转载请注明出处:https://www.jqgcy.com/xitongjiaocheng/126944.html

JavaScript 的 Symbol.toPrimitive 怎么使用
上一篇 2026-07-19 17:00
C++如何使用std::invoke调用任何可调用对象
下一篇 2026-07-19 17:00

相关推荐