mysql菜鸟教程
15.3 提交与回滚:COMMIT和ROLLBACK
在上一节中,我们学习了如何用 START TRANSACTION 开始一个事务。但事务开始后,如何让它生效或取消呢?这就涉及两个关键命令:COMMIT 和 ROLLBACK。它们是事务的终点,决定了事务内所有操作的最终命运。
一、COMMIT:让修改永久生效
COMMIT 语句用于提交当前事务,即将事务中所有未提交的更改永久保存到数据库中。提交后,事务持有的锁会被释放,其他事务可以看到这些更改(取决于隔离级别)。
基本语法
COMMIT;
示例:成功的转账
START TRANSACTION; UPDATE accounts SET balance = balance - 100 WHERE account_id = 'A'; UPDATE accounts SET balance = balance + 100 WHERE account_id = 'B'; COMMIT; -- 两条更新永久生效
执行 COMMIT 后,数据的变化就无法通过 ROLLBACK 撤消了。
二、ROLLBACK:撤销所有更改
ROLLBACK 语句用于回滚当前事务,即撤销事务中所有已执行的修改,将数据库恢复到事务开始之前的状态。回滚后,事务持有的锁也会被释放。
基本语法
ROLLBACK;
示例:余额不足,取消转账
START TRANSACTION; SELECT @bal := balance FROM accounts WHERE account_id = 'A'; -- 假设在应用程序中检查 @bal,发现小于 100,则执行回滚 ROLLBACK; -- 任何未提交的修改都被撤销
如果在 ROLLBACK 之前已经执行了一些 UPDATE,这些 UPDATE 的影响会被完全消除。
三、事务的生命周期
一个典型的事务经历以下阶段:
1、开始:START TRANSACTION 或 BEGIN。
2、操作:执行一条或多条 SQL 语句(INSERT、UPDATE、DELETE 等)。
3、结束:COMMIT 或 ROLLBACK。
如果提交,更改永久生效。
如果回滚,更改全部撤销。
4、后续:事务结束后,数据库回到空闲状态。如果 AUTOCOMMIT 为 1,下一条语句会自动开始新事务;如果为 0,则需要再次 START TRANSACTION 或执行语句(会隐式开始新事务)。
四、自动提交模式与显式提交
默认情况下,MySQL 是自动提交模式(AUTOCOMMIT=1)。这意味着每一条 SQL 语句执行后都会自动提交,相当于每条语句都隐含了 COMMIT。要使用多语句事务,必须显式关闭自动提交或使用 START TRANSACTION。
查看当前自动提交状态
SHOW VARIABLES LIKE 'autocommit';
在自动提交模式下使用事务
SET AUTOCOMMIT = 0; -- 关闭自动提交 -- 之后的所有语句不会自动提交,需要手动 COMMIT 或 ROLLBACK UPDATE accounts ...; UPDATE accounts ...; COMMIT; -- 手动提交 -- 如果要重新开启自动提交 SET AUTOCOMMIT = 1;
更常见的做法是不改变自动提交设置,而是显式使用 START TRANSACTION,这样事务结束后会自动恢复原来的自动提交模式。
START TRANSACTION; UPDATE ...; UPDATE ...; COMMIT; -- 事务结束,自动提交模式恢复原状
五、结合保存点的部分回滚
ROLLBACK 默认会回滚整个事务。但如果你只想撤销事务的一部分,可以使用保存点(SAVEPOINT)。
示例:部分回滚
START TRANSACTION;
INSERT INTO logs(message) VALUES('开始转账');
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 已扣款
ROLLBACK TO SAVEPOINT after_deduct; -- 撤销对 B 的修改,保留 A 的扣款
-- 可以继续执行其他操作
UPDATE accounts SET balance = balance + 100 WHERE account_id = 'C';
COMMIT; -- 最终只提交 A 扣款和 C 加款注意:
回滚到保存点不会结束事务,只是撤销了保存点之后的修改。
保存点之前的修改依然存在,可以继续操作或最终提交。
执行 COMMIT 或整体 ROLLBACK 后,所有保存点自动释放。
六、注意事项
DDL 语句的隐式提交:CREATE、ALTER、DROP、TRUNCATE 等数据定义语言(DDL)语句会隐式提交当前事务。这意味着如果你在一个事务中执行了 DDL,之前的修改会被自动提交,且之后无法回滚。因此,事务中应避免混用 DDL。
事务未提交的后果:如果事务开始后既没有 COMMIT 也没有 ROLLBACK,事务会一直保持打开状态,可能持有锁并阻止其他会话。长时间未提交的事务是性能杀手,务必及时结束事务。
断开连接时的处理:如果客户端会话在没有显式提交或回滚的情况下断开连接,MySQL 会自动回滚该会话中未提交的事务。
COMMIT 和 ROLLBACK 后的事务状态:执行完 COMMIT 或 ROLLBACK 后,当前事务结束。如果你之前是显式 START TRANSACTION,那么系统回到事务未开始的状态,下一条语句如果是普通 SQL,会遵循当前的自动提交模式。如果想开始另一个事务,需要再次 START TRANSACTION。
七、综合示例:带条件判断的转账
在实际应用中,事务往往与业务逻辑结合。下面是一个简化的存储过程示例,演示如何在事务中使用条件回滚:
DELIMITER // CREATE PROCEDURE Transfer( IN from_account VARCHAR(10), IN to_account VARCHAR(10), IN amount DECIMAL(10,2), OUT success BOOLEAN ) BEGIN DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN ROLLBACK; SET success = FALSE; END; START TRANSACTION; -- 检查余额是否足够 IF (SELECT balance FROM accounts WHERE account_id = from_account) < amount THEN ROLLBACK; SET success = FALSE; ELSE UPDATE accounts SET balance = balance - amount WHERE account_id = from_account; UPDATE accounts SET balance = balance + amount WHERE account_id = to_account; COMMIT; SET success = TRUE; END IF; END // DELIMITER ;
调用:
CALL Transfer('A', 'B', 100, @ok);
SELECT @ok;八、小结
提交让修改成为现实,回滚让修改化为泡影。
始终确保事务有明确的终点(COMMIT 或 ROLLBACK),避免长事务。
注意 DDL 的隐式提交,不要在事务中随意使用。
结合保存点可以实现更精细的控制。
掌握了提交与回滚,你就真正掌握了事务的核心操作。下一节我们将讨论不同隔离级别下的并发问题,以及如何选择合适的隔离级别。

发表评论
所有评论