什么是mysql事务_mysql事务基础概念解析

10次阅读

MySQL 事务是 InnoDB 引擎支持的 DML 操作逻辑集合,必须全部成功或全部失败;默认 autocommit= 1 导致转账可能数据不一致;需显式使用 START TRANSACTION 和 COMMIT 保障原子性。

什么是 mysql 事务_mysql 事务基础概念解析

MySQL 事务 是一组 DML 操作(INSERTUPDATEDELETE)的逻辑集合,它必须 全部成功,或全部失败——没有“一半生效”的中间状态。这是 InnoDB 存储引擎提供的核心能力,MyISAM 等引擎不支持事务,直接绕过这个机制。


为什么 默认转账会出错?因为 autocommit=1

你写两条 UPDATE 转账语句,没加任何事务控制,结果张三扣了钱、李四没到账——这不是 bug,是 MySQL 的默认行为在起作用:

  • autocommit 默认为 1,即每条 DML 语句单独成一个事务,自动提交
  • 第一条 UPDATE 执行完立刻落盘;第二条若因网络中断、程序崩溃、SQL 错误而失败,已提交的第一条无法撤回
  • 这就是典型的“数据不一致”:总金额凭空减少

✅ 正确做法:显式关闭自动提交,用 START TRANSACTION 包裹操作:

SET autocommit = 0; START TRANSACTION; UPDATE account SET money = money - 100 WHERE name = '张三'; UPDATE account SET money = money + 100 WHERE name = '李四'; COMMIT;

⚠️ 注意:SET autocommit = 0 只对当前会话有效;生产环境更推荐在代码里用 BEGIN/COMMIT 显式控制,避免依赖会话级配置。


事务不是万能锁:ACID 里最常被误解的是“一致性”

很多人以为“事务保证数据正确”,其实 consistency 不是数据库自动校验业务规则,而是指:事务前后,数据库必须满足你定义的约束(如主键、外键、CHECK、唯一索引等)。

  • 如果你没给 money 字段加 CHECK(money>= 0),事务照样允许余额变成 -500 —— 这不算违反 ACID,只是你的业务一致性没落地
  • 转账中 A 减、B 增,但没加外键或触发器校验双方账户存在?事务提交了,但业务上已经错了
  • COMMIT 成功 ≠ 业务正确;它只代表“数据库层面没违反约束”

? 真正兜底要靠:约束定义 + 应用层校验 + 幂等设计(比如用转账单号防重)


事务隔离级别不是调高就安全:REPEATABLE READ 也挡不住幻读

MySQL 默认隔离级别是 REPEATABLE READ,它能防止脏读、不可重复读,但 ** 无法完全避免幻读 **(比如 SELECT …… FOR UPDATE 范围内新插入一行,再次查出来多了一条)。

  • READ COMMITTED:每次 SELECT 都读最新已提交版本 → 可能不可重复读,但幻读概率更低
  • REPEATABLE READ:基于 MVCC 快照读,可重复读,但快照不覆盖新插入行 → 幻读仍可能发生
  • SERIALIZABLE:加范围锁强制串行,性能差,一般不用

? 实际选择建议:

  • 普通 Web 应用:保持默认 REPEATABLE READ,幻读场景手动加 SELECT …… FOR UPDATE 或用唯一业务键替代范围查询
  • 强一致性 金融 场景:别只调隔离级别,配合乐观锁(version 字段)或分布式事务框架(如 Seata)

事务生命周期结束的 4 种方式,第 3 种最容易被忽略

事务不是开了就一直挂着,它会在以下任一情况自动终止:

  • COMMITROLLBACK 显式结束
  • 执行了 DDL(如 ALTER TABLE)、DCL(如 GRANT)——这些语句会隐式提交当前事务
  • 客户端连接异常断开(如超时、kill connection) → MySQL 会自动回滚未提交事务
  • 用户会话正常退出(如命令行 exit)→ 同样自动回滚

⚠️ 关键陷阱:应用层长事务(比如导出报表 + 更新状态)若没设好连接超时,可能卡住锁、拖垮并发。务必在代码里明确 COMMITROLLBACK,不要依赖自动清理。

text=ZqhQzanResources