MySQL 事务开始用 BEGIN
还是 START TRANSACTION
?
两者在功能上完全等价,
BEGIN是
START TRANSACTION的别名,但官方文档明确建议优先用
START TRANSACTION。原因在于
BEGIN容易和存储过程中的
BEGIN...END块混淆,尤其在动态拼接 SQL 或 ORM 自动注入场景下可能引发歧义。
START TRANSACTION更语义清晰,明确表示“开启一个新事务”
BEGIN在某些旧版客户端(如早期 phpMyAdmin)中可能被误解析为语句块起始 不支持嵌套事务:即使写两次
START TRANSACTION,MySQL 也只认最外层,内部的会被忽略
什么情况下 COMMIT
不会真正提交?
COMMIT失效通常不是语句本身的问题,而是事务上下文已丢失或被隐式结束。常见于以下场景: 执行了非事务性语句(如
CREATE TABLE ... ENGINE=MyISAM),MySQL 会自动提交当前事务 执行了 DDL 语句(如
ALTER TABLE、
DROP INDEX),InnoDB 会强制提交当前事务并开启新事务 连接异常断开(如超时、客户端崩溃),未
COMMIT的修改直接丢弃 使用了自动提交模式(
AUTOCOMMIT=1),单条 DML 语句执行完立即生效,
COMMIT无实际作用
验证方式:执行
SELECT @@autocommit;,返回
0表示手动提交模式启用。
ROLLBACK
能回退到任意中间点吗?
不能。MySQL 默认不支持多级回滚,
ROLLBACK总是回退到事务最开始的位置。若需部分回滚,必须配合
SAVEPOINT:
START TRANSACTION;
INSERT INTO users (name) VALUES ('Alice');
SAVEPOINT sp1;
INSERT INTO users (name) VALUES ('Bob');
SAVEPOINT sp2;
INSERT INTO users (name) VALUES ('Charlie');
ROLLBACK TO SAVEPOINT sp1; -- 只撤销 'Bob' 和 'Charlie'
COMMIT;
SAVEPOINT名称区分大小写,且仅在当前事务内有效 回滚到某个
SAVEPOINT后,该点之后定义的其他
SAVEPOINT自动失效 事务结束后所有
SAVEPOINT全部清除,无需手动释放
事务控制语句对锁和并发的影响
事务持续期间,InnoDB 会根据访问的数据行持有锁(如记录锁、间隙锁),这些锁直到
COMMIT或
ROLLBACK才释放。这意味着: 长事务(长时间未
COMMIT)会拖住锁,导致其他会话阻塞,甚至触发
Lock wait timeout exceeded
ROLLBACK操作本身可能很慢——它需要逆向执行所有已做的变更,尤其是涉及大量更新时 显式使用
START TRANSACTION后,哪怕只读查询(如
SELECT)在可重复读(RR)隔离级别下也会加一致性读锁,影响并发性能
线上业务中,事务应尽量短小,避免在事务内做 HTTP 请求、文件读写等不可控耗时操作。
