SQL BEGIN、COMMIT、ROLLBACK 使用方法

12次阅读

事务控制语句必须成对出现在同一连接中,begin 开启事务仅对当前连接有效,断连则自动回滚;commit 使修改持久化并可见,rollback 撤销所有操作;ddl 隐式提交,嵌套事务多为语法糖,savepoint 支持子事务;autocommit 状态决定 begin 是否生效,orm 通常自动管理但原生 sql 需手动处理。

SQL BEGIN、COMMIT、ROLLBACK 使用方法

事务控制语句必须成对出现在同一个连接里

MySQL、PostgreSQL、SQL Server 等主流数据库中,BEGIN(或 START TRANSACTION)开启的事务,只对当前数据库连接有效。一旦连接断开,未提交的事务自动回滚,COMMITROLLBACK 都失效。

  • BEGIN 不是函数,不能加括号;某些数据库(如 SQL Server)用 BEGIN TRAN,但 PostgreSQL 和 MySQL 只认 BEGINSTART TRANSACTION
  • 执行 COMMIT 后,所有已修改的数据才真正写入磁盘并可见给其他连接;之前只在本连接内可见
  • 如果程序中途崩溃、网络中断或显式调用 ROLLBACK,所有 INSERT/UPDATE/DELETE 操作全部撤销,就像没发生过
  • 注意:DDL 语句(如 CREATE TABLEDROP INDEX)在多数数据库中会隐式触发 COMMIT,导致前面的事务提前结束

嵌套事务在大多数数据库里只是语法糖

BEGINBEGIN 这种写法,MySQL 完全不支持;PostgreSQL 允许但实际没有嵌套语义——ROLLBACK 总是回滚到最外层 BEGIN,不是最近一层。

  • PostgreSQL 提供 SAVEPOINT 实现真正的“子事务”控制:SAVEPOINT sp1ROLLBACK TO sp1
  • SQL Server 支持命名事务(BEGIN TRAN t1),但 ROLLBACK TRAN t1 仍会回滚整个外部事务,除非配合 SAVE TRANSACTION
  • 不要依赖“嵌套 BEGIN”来分段控制,容易误判回滚范围

自动提交模式(autocommit)关不关,直接影响 BEGIN 是否生效

默认情况下,MySQL 客户端和 JDBC 驱动都开启 autocommit;此时每条 INSERT 都自动 COMMITBEGIN 之后的操作看似在事务里,其实只要 autocommit 开着,BEGIN 就被忽略。

  • 确认当前状态:执行 SELECT @@autocommit(MySQL)或 SHOW VARIABLES LIKE 'autocommit'
  • 关闭它:SET autocommit = 0(MySQL),或用客户端配置(如 Python 的 conn.autocommit = False
  • PostgreSQL 默认 autocommit 关闭,所以 BEGIN 总是有效;但 pgAdmin 等 GUI 工具可能默认开启,需检查设置
  • ORM(如 Django、SQLAlchemy)通常自动管理 autocommit,但手动写原生 SQL 时必须自己处理

COMMIT 失败通常意味着连接已断或事务被强制终止

正常情况下 COMMIT 不会报错;一旦出现 ERROR 1312 (HY000): COMMIT is not allowed in a stored function or trigger 这类提示,说明你正在函数 / 触发器里执行了它——这是数据库硬性限制。

  • 常见错误现象:COMMIT 执行后查不到刚插入的数据?先确认是否忘了 SELECT 时加了 FOR UPDATE 或隔离级别影响
  • 长时间未 COMMIT 的事务会占用锁、阻塞其他操作,MySQL 中可通过 SELECT * FROM information_schema.INNODB_TRX 查看活跃事务
  • 不要在循环里反复 COMMIT,尤其大批量写入时——每次 COMMIT 都有 I/O 开销;建议每 1000 行左右批量提交一次

事务边界不是靠代码缩进或注释决定的,而是由连接生命周期、autocommit 设置和显式语句共同锁定的。漏掉一个 SET autocommit = 0,或者在 ORM 里混用原生 SQL 和事务方法,都可能导致你以为在事务里,其实每条语句都在单独提交。

text=ZqhQzanResources