方式一:显式开启事务(BEGIN/START TRANSACTION)
基本用法和语义
在 MySQL 中,显式开启事务是最直接的方式。通过 BEGIN 或 START TRANSACTION,可以将当前会话带入一个原子执行单元。
开启后,后续的 DML 语句将处于同一个事务中,直到执行 COMMIT 或 ROLLBACK。此时,autocommit 的状态对该会话通常变为不可自动提交。
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT; -- 或 ROLLBACK
需要注意的是,在生产环境中,BEGIN 与 START TRANSACTION 是等价的,选择其一即可,但要保持一致性以避免读取脏数据的风险。
生产环境中的注意点
为了确保并发安全,事务粒度应尽量小,避免在事务中执行耗时的查询或等待操作,这样可以降低死锁概率。
在多语句事务中,错误处理和回滚路径要清晰,不要在捕获异常后继续执行未完成的变更。
请确保数据库引擎为 InnoDB,因为只有 InnoDB 才提供行级锁和崩溃恢复能力,其他引擎如 MyISAM 不支持事务。
方式二:通过关闭 autocommit 启动事务
基本用法与触发机制
除了显式调用 BEGIN,现在也有一种常见做法是通过将会话级别的自动提交关闭来开启事务,即 SET autocommit = 0。
关闭自动提交后,后续的第一条语句将进入事务,直到应用端显式执行 COMMIT 或 ROLLBACK。此模式多见于糖化的脚本或某些 ORM 的特定场景。
SET autocommit = 0;
UPDATE inventory SET qty = qty - 1 WHERE product_id = 101;
UPDATE inventory SET qty = qty + 1 WHERE product_id = 202;
COMMIT; -- 或 ROLLBACK
需要明确的是,当你使用 SET autocommit = 0,该设置只影响当前会话,连接池中的每个连接可能需要单独设置,否则会导致事务边界混乱。
生产环境中的注意点
在生产环境里,不要长时间保留未提交的事务,否则会锁住相关数据,降低并发性并可能引起潜在的死锁。

请在应用层实现正确的异常处理和最终性提交逻辑,确保在异常路径也能执行 ROLLBACK,以避免数据不一致。
如果使用连接池,务必确保在每次请求结束后提交或回滚并释放连接,避免连接长时间处于事务状态。


