事务必须显式开启,begin或start transaction缺一不可;mysql默认autocommit=1,多条dml需先开启事务才能统一提交或回滚。

事务必须显式开启,BEGIN 或 START TRANSACTION 缺一不可
MySQL 默认是自动提交模式(autocommit=1),每条 DML 语句单独成事务,执行完立刻生效。想把多条语句打包进一个事务,必须先显式开启——只写 COMMIT 或 ROLLBACK 没用,它们不会触发隐式开始。
常见错误:直接写 UPDATE t1 SET x=1; UPDATE t2 SET y=2; COMMIT;,结果两条更新各自提交,无法回滚。
-
BEGIN和START TRANSACTION完全等价,任选其一即可 - 不推荐用
BEGIN WORK,虽兼容但冗余 - 开启后,后续所有 DML(
INSERT/UPDATE/DELETE)都暂存在当前事务中,直到COMMIT或ROLLBACK
SAVEPOINT 不是必需的,但能解决部分回滚需求
标准事务只有全提交或全回滚两种结局。如果中间某步出错,又不想放弃前面已成功的操作,就得靠 SAVEPOINT 设立标记点。
例如:插入主表、插入从表、更新统计表 —— 若第三步失败,只回滚到第二步之后的状态,保留前两步。
- 定义:
SAVEPOINT sp1;,名字可自定义,同一事务内可设多个 - 回滚到某点:
ROLLBACK TO SAVEPOINT sp1;(注意不是ROLLBACK TO sp1) - 释放某个保存点:
RELEASE SAVEPOINT sp1;,不影响事务本身 - 事务结束(
COMMIT或ROLLBACK)会自动清除所有保存点
隐式提交语句会让事务意外终止
有些 SQL 语句执行时会强制提交当前事务,哪怕你没写 COMMIT,事务也立刻结束。这是最容易踩坑的地方,尤其在存储过程或混合 DDL/DML 场景中。
典型触发隐式提交的语句包括:CREATE TABLE、DROP TABLE、ALTER TABLE、TRUNCATE TABLE、LOCK TABLES、FLUSH LOGS 等。
- 示例:
BEGIN; INSERT INTO t VALUES(1); CREATE TABLE tmp(id INT); INSERT INTO t VALUES(2); COMMIT;→ 实际只有最后一条INSERT受事务保护 -
SELECT不会隐式提交,但SELECT ... FOR UPDATE或SELECT ... LOCK IN SHARE MODE属于事务内加锁操作,仍需在事务中使用 - DDL 类操作尽量放在事务外,或确认是否真需要与 DML 绑定
事务隔离级别影响可见性,SET TRANSACTION ISOLATION LEVEL 必须在 BEGIN 前设置
MySQL 的默认隔离级别是 REPEATABLE READ,但如果你需要读已提交(READ COMMITTED)来避免间隙锁或适配其他数据库行为,得手动改——而且时机很关键。
错误写法:BEGIN; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; → 此时事务已开启,该语句无效,级别仍是启动时的默认值。
- 正确方式:在
BEGIN前执行,如SET TRANSACTION ISOLATION LEVEL READ COMMITTED; BEGIN; - 也可用会话级设置:
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;,之后所有新事务都生效 -
READ UNCOMMITTED和SERIALIZABLE同理,不能在事务中动态切换
BEGIN 形同虚设。实际写业务逻辑时,别只盯着 COMMIT 写在哪,先确认事务是不是真的从你想的位置开始了。










