事务是什么
事务把多条语句打包成一个原子单元:要么全部生效,要么全部不生效。InnoDB 默认隔离级别是 REPEATABLE READ,配合行锁与多版本并发控制实现一致性读,同一事务内多次读取同一行会得到相同结果。开启事务用 START TRANSACTION 或 BEGIN,结束用 COMMIT 提交、ROLLBACK 回滚,中间还可以用保存点做局部回退。事务越长,占用的回滚段、日志与锁就越多。
基本信息
| 用途 | 把多条语句组成原子操作 |
|---|---|
| 语句 | START TRANSACTION / COMMIT / ROLLBACK / SAVEPOINT |
| 默认隔离级别 | REPEATABLE READ(可重复读) |
| 提交模式 | autocommit 默认开启,单条语句自成一个事务 |
| 锁释放 | 行锁在事务提交或回滚后释放 |
| 主要风险 | 长事务占用回滚段、阻塞 DDL、放大复制延迟 |
典型使用场景
- 转账类操作:一侧扣减与另一侧增加必须在同一事务里
- 下单流程:写订单、扣库存、记流水,任一步失败整体回滚
- 批量数据修复:全部成功或全部放弃,避免留下半成品数据
- 一致性读:同一事务内多次读同一数据结果稳定,适合对账
- 配合保存点做部分回滚:一批操作里的某几项可单独撤销
- 数据导入分批提交,把单个事务的规模控制在合理范围
基本事务
基本事务
START TRANSACTION; # 显式开启事务
UPDATE accounts SET balance = balance - 100 WHERE id = 1; # 转出方扣减
UPDATE accounts SET balance = balance + 100 WHERE id = 2; # 转入方增加
COMMIT; # 提交;出问题改为 ROLLBACK 整体回滚保存点的用法
保存点的用法
START TRANSACTION;
INSERT INTO audit_log(msg) VALUES ('begin'); # 事务内的第一次写入
SAVEPOINT sp1; # 标记回退点
UPDATE counters SET cnt = cnt + 1 WHERE id = 7;
ROLLBACK TO sp1; # 只撤销保存点之后的操作,前面写入保留
COMMIT; # 第一部分照常提交事务行为要点
| 项目 | 说明 | 注意 |
|---|---|---|
| autocommit | 默认开启,单条语句即一个事务 | 显式开启后多条语句才在同一事务 |
| START TRANSACTION | 开启事务 | BEGIN 是等价写法 |
| COMMIT | 提交并使修改持久化 | 提交之后无法再回滚 |
| ROLLBACK | 回滚全部未提交修改 | 回滚完成后相关锁才释放 |
| SAVEPOINT | 事务内部的回退标记 | 可设置多个并回退到指定标记 |
| 隐式提交 | DDL 等语句会结束当前事务 | 建表改表前先提交,别混在业务事务里 |
| 隔离级别 | 默认可重复读 | 同一事务内读取结果保持稳定 |
可重复读下事务的一致性快照在第一次读时建立,因此长事务会一直看到旧数据;对账、报表类任务如果在事务里停留过久,读到的可能是过期状态。
长事务会持续占用回滚段空间、阻塞在线改表,并把主从延迟放大;事务里不要夹带远程调用、文件读写或人工确认这类等待操作。
只读任务可以显式开启只读事务,减少锁与快照维护的开销;报表与数据核对类作业适合这种用法,避免误写的同时也降低了并发干扰。
事务使用检查清单
- 事务边界尽量短,先算好数据再开启事务
- 不要在事务里做远程调用或等待人工操作
- DDL 与业务事务分开执行,避免隐式提交打断边界
- 批量写入分批提交,控制单个事务的行数
- 捕获异常后显式回滚,别让连接带着未提交修改归还
- 关注锁等待与死锁日志,定期检查长事务
事务提交后修改对其他会话才可见;写多读少的场景可以把多批小事务合并成适度的大事务来摊薄日志开销,但要以不影响锁等待与复制延迟为前提。