MySQL 【事务】

【MySQL 笔记】事务(Transaction)详解

事务是 MySQL 中保证数据一致性可靠性的最核心机制,尤其在涉及多条 SQL 语句需要“要么全成功、要么全失败”的场景(如转账、订单创建扣库存、下单减积分等)时,几乎是必须使用的。

一、事务的四大核心特性(ACID)

特性英文通俗解释MySQL 中的体现方式
原子性Atomicity要么全做,要么全不做undo log + MVCC + 回滚
一致性Consistency事务前后,数据库从一个一致状态到另一个一致状态约束(主键、外键、CHECK)+ 业务逻辑 + 隔离级别
隔离性Isolation不同事务之间互不干扰锁 + MVCC(多版本并发控制)
持久性Durability事务一旦提交,数据永久保存redo log + 双写缓冲 + binlog(取决于刷盘策略)

一句话总结
ACID 让你的转账操作不会出现“钱扣了但没到账”或“别人看到中间状态”的灾难。

二、MySQL 事务基本语法

-- 方式一:显式事务(最常用、最清晰)
START TRANSACTION;          -- 或 BEGIN;
    UPDATE accounts SET balance = balance - 100 WHERE id = 1;
    UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;                     -- 提交(成功)
-- ROLLBACK;                -- 回滚(失败或手动取消)

-- 方式二:自动提交(默认行为)
SET autocommit = 1;         -- 默认就是 1
UPDATE ...;                 -- 每条语句立即提交

常用组合写法(生产推荐)

START TRANSACTION;

-- 核心业务逻辑
UPDATE account_a SET balance = balance - 500 WHERE id = 1001 AND balance >= 500;
-- 检查是否扣款成功(影响行数)
SET @affected = ROW_COUNT();

IF @affected = 0 THEN
    ROLLBACK;
    SELECT '余额不足' AS msg;
ELSE
    UPDATE account_b SET balance = balance + 500 WHERE id = 1002;
    COMMIT;
    SELECT '转账成功' AS msg;
END IF;

三、MySQL 支持的事务隔离级别(最重要!)

MySQL InnoDB 默认隔离级别:REPEATABLE READ(可重复读)

隔离级别脏读不可重复读幻读MySQL 默认备注 / 实际表现(InnoDB)
READ UNCOMMITTED基本没人用(能读到未提交的数据)
READ COMMITTEDOracle 默认每次 SELECT 都读最新提交版本(电商常见)
REPEATABLE READ有(但 InnoDB 通过间隙锁极大减少)MySQL 默认同一事务内多次读相同数据结果一致
SERIALIZABLE最高隔离,性能最差(几乎所有读写都加锁)

InnoDB 在 REPEATABLE READ 下的特殊行为(非常重要):

  • 通过 MVCC + 间隙锁(Gap Lock) + Next-Key Lock,在大多数场景下解决了幻读
  • 严格意义上仍然存在幻读可能性(只在特定加锁读 + 插入场景)
  • 实际生产中,REPEATABLE READ 已经足够安全,性能也最好

四、事务常见使用场景 & 推荐隔离级别

业务场景推荐隔离级别为什么是否需要显式事务
银行转账、支付扣款REPEATABLE READ防止脏读 + 不可重复读,间隙锁防超卖必须
电商下单减库存REPEATABLE READ防止超卖(结合 SELECT … FOR UPDATE)必须
普通查询报表READ COMMITTED追求最新数据,接受不可重复读可选
高并发日志写入READ COMMITTED性能优先,不关心幻读通常不需要
数据一致性要求极高SERIALIZABLE几乎杜绝并发问题(但并发性能极差)必须

五、事务相关重要系统变量 & 查看方式

-- 查看当前会话隔离级别
SELECT @@transaction_isolation;           -- 或 @@tx_isolation(旧版)

-- 查看全局默认隔离级别
SELECT @@global.transaction_isolation;

-- 修改当前会话隔离级别(只影响当前连接)
SET SESSION transaction_isolation = 'READ-COMMITTED';

-- 修改全局默认(重启后失效,需写配置文件)
SET GLOBAL transaction_isolation = 'READ-COMMITTED';

六、生产中事务常见坑 & 最佳实践(2026 年视角)

  1. 长事务 是最大杀手(锁住资源很久)
  • 避免在事务里做大批量操作、循环查询
  • 事务尽量控制在 100ms~几秒内
  1. 忘记 COMMIT / ROLLBACK
  • 连接池环境下会自动回滚,但显式写更安全
  1. 在事务里混用 DDL
  • DDL(如 ALTER TABLE)会隐式提交当前事务
  1. SELECT 不加锁就认为安全
  • 普通 SELECT 不加锁 → 快照读
  • SELECT … FOR UPDATE / LOCK IN SHARE MODE → 当前读(加锁)
  1. 推荐写法模板(转账/扣减库存)
START TRANSACTION;

SELECT balance FROM accounts WHERE id = 1 FOR UPDATE;  -- 行锁

-- 业务判断
UPDATE accounts SET balance = balance - 100 WHERE id = 1 AND balance >= 100;

IF ROW_COUNT() = 0 THEN
    ROLLBACK;
ELSE
    UPDATE accounts SET balance = balance + 100 WHERE id = 2;
    COMMIT;
END IF;

下一期预告建议:MySQL 锁机制详解(行锁、表锁、间隙锁、Next-Key Lock、MVCC)

有哪种事务场景你项目里最常遇到(转账、秒杀、下单、批量更新等),或者对隔离级别、幻读还有疑问,欢迎留言,我们可以针对性深入~
祝大家事务写得稳,数据不丢不乱!🔄

文章已创建 5186

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部