mysql菜鸟教程
15.2 开始事务:START TRANSACTION
在上一节中,我们学习了事务的基本概念和 ACID 原则。现在,让我们亲自动手,学习如何在 MySQL 中开始一个事务。掌握 START TRANSACTION 命令是使用事务的第一步,它将开启一个逻辑工作单元,之后的所有 SQL 语句都将被视为同一个事务的一部分,直到你明确地提交或回滚。
一、开始事务的基本语法
在 MySQL 中,开始事务有三种等效的方式:
START TRANSACTION; 或者 BEGIN; 或者 BEGIN WORK;
这三种写法作用完全相同,都是显式地开始一个新的事务。通常推荐使用 START TRANSACTION,因为它的语义最清晰。
示例:开始一个简单的转账事务
START TRANSACTION; UPDATE accounts SET balance = balance - 100 WHERE account_id = 'A'; UPDATE accounts SET balance = balance + 100 WHERE account_id = 'B'; COMMIT; -- 提交事务,使修改永久生效
在这个例子中,从 START TRANSACTION 到 COMMIT 之间的两条 UPDATE 语句构成了一个原子操作。
二、自动提交模式(AUTOCOMMIT)
在理解显式事务之前,需要先了解 MySQL 的默认行为。默认情况下,MySQL 以自动提交(autocommit) 模式运行。这意味着每条单独的 SQL 语句都会在其执行完成后自动提交,相当于每条语句都隐含地包裹在事务中。
你可以通过以下命令查看当前的自动提交状态:
SHOW VARIABLES LIKE 'autocommit';
默认值是 ON(1)。
关闭自动提交
如果你想隐式地开始事务(即不显式写 START TRANSACTION,但希望多条语句作为一个事务),可以临时关闭自动提交:
SET AUTOCOMMIT = 0; -- 关闭自动提交 -- 之后的所有语句都属于同一事务,直到手动 COMMIT 或 ROLLBACK UPDATE accounts ...; UPDATE accounts ...; COMMIT; -- 提交后,事务结束,但 autocommit 仍为 0
当 AUTOCOMMIT = 0 时,你执行的每一条 SQL 都不会立即提交,而是累积起来,直到你执行 COMMIT 或 ROLLBACK。执行 COMMIT 后,下一个事务会自动开始(仍然不自动提交)。
注意:关闭自动提交后,如果忘记提交,修改可能不会持久化,且会持有锁,容易造成死锁。因此,对于初学者,建议显式使用 START TRANSACTION 来明确事务边界。
三、提交与回滚
事务开始后,你可以通过以下两种方式结束它:
COMMIT:提交事务,使所有修改永久生效。
ROLLBACK:回滚事务,撤销所有修改,数据库恢复到事务开始前的状态。
示例:带错误处理的事务
假设我们在转账过程中检测到余额不足,需要回滚整个事务:
START TRANSACTION; SELECT balance FROM accounts WHERE account_id = 'A' FOR UPDATE; -- 加锁检查 -- 假设应用程序逻辑判断余额不足 ROLLBACK; -- 撤销任何修改(如果有)
如果没有显式提交或回滚,事务会一直保持打开状态,直到会话结束(此时会自动回滚)。
四、保存点(SAVEPOINT)
有时候,你可能不想回滚整个事务,而只想回滚到事务中的某个中间点。这时可以使用保存点(SAVEPOINT)。
语法
SAVEPOINT 保存点名称; ROLLBACK TO [SAVEPOINT] 保存点名称; RELEASE SAVEPOINT 保存点名称; -- 删除保存点
示例:在复杂事务中使用保存点
START TRANSACTION; UPDATE accounts SET balance = balance - 100 WHERE account_id = 'A'; SAVEPOINT after_deduct; UPDATE accounts SET balance = balance + 100 WHERE account_id = 'B'; -- 假设发现 B 账户有问题,但 A 账户扣款没问题,只想回滚到 after_deduct 点 ROLLBACK TO SAVEPOINT after_deduct; -- 现在事务处于 after_deduct 点的状态,A 已扣款,B 未加款 -- 可以继续执行其他操作,最后提交 UPDATE accounts SET balance = balance + 100 WHERE account_id = 'C'; COMMIT;
重要:
保存点只能在事务内部使用。
回滚到保存点不会结束事务,只是撤销了保存点之后的修改。
事务提交或整体回滚后,所有保存点自动释放。
五、隐式提交的语句
有些 SQL 语句在执行前会隐式地提交当前事务,就像执行了一个 COMMIT 一样。这些语句通常包括:
数据定义语言(DDL)语句:CREATE、ALTER、DROP、TRUNCATE、RENAME 等。
权限管理语句:GRANT、REVOKE、SET PASSWORD 等。
锁表语句:LOCK TABLES、UNLOCK TABLES。
管理语句:ANALYZE TABLE、CACHE INDEX、CHECK TABLE、OPTIMIZE TABLE、REPAIR TABLE 等。
因此,在一个显式事务中,如果你执行了 DDL 语句,前面的修改会被自动提交,后续的操作将属于一个新的事务。这可能会破坏事务的原子性,所以事务中应尽量避免混用 DDL。
六、综合示例:完整的银行转账事务
-- 关闭自动提交(可选,但为了清晰我们显式开始事务) SET AUTOCOMMIT = 0; START TRANSACTION; -- 检查账户 A 余额是否足够 SELECT @bal := balance FROM accounts WHERE account_id = 'A' FOR UPDATE; IF @bal >= 100 THEN UPDATE accounts SET balance = balance - 100 WHERE account_id = 'A'; UPDATE accounts SET balance = balance + 100 WHERE account_id = 'B'; COMMIT; SELECT '转账成功' AS result; ELSE ROLLBACK; SELECT '余额不足' AS result; END IF;
注意:上面的 IF 是伪代码,实际需要在存储过程或应用程序中实现。在纯 SQL 中,可以通过条件判断结合事务,但通常是在应用程序中编写逻辑。
七、小结
使用 START TRANSACTION(或 BEGIN)显式开始一个事务。
事务开始后,后续的 SQL 语句属于同一个工作单元,直到 COMMIT 或 ROLLBACK。
MySQL 默认是自动提交模式,可以通过 SET AUTOCOMMIT = 0 关闭,但显式事务更清晰。
保存点允许部分回滚,增加了事务的灵活性。
注意某些 DDL 语句会隐式提交当前事务,应避免在事务中间使用。
掌握开始事务的方法后,下一节我们将学习如何正确地提交和回滚事务,以及在并发环境下可能遇到的各种问题。

发表评论
所有评论