MySQL 事务

原子性、一致性、隔离性、持久性

一致性:唯一的“终点”

  • A(原子性)、I(隔离性)、D(持久性) 都是手段
  • C(一致性) 才是目的

数据库做那么多的日志和锁,本质上是为了保证:无论外界怎么折腾(断电、并发、报错),数据最终都是对的

持久性与原子性的“守护神”:Redo 与 Undo

数据库的操作是在内存(Buffer Pool)中完成的,如果还没有写入磁盘就断电了怎么办?如果写到一阗报错了怎么回滚?

Redo Log(重做日志):为了“不丢失”

磁盘 I/O 是极慢的。为了性能,MySQL 不会每次修改都刷盘,而是先写到内存,并记录一份 Redo Log

它记录的是“在某个数据页做了什么修改”。就像是你做题时的草稿本,即使你最后忘了把答案写进答题卡(磁盘),只要草稿本在,老师(数据库重启后)就能帮你把分数找回来

Undo Log(回滚日志):为了“不认账”

原子性要求事务要么全成功,要么全失败。

当你执行一条 INSERT,Undo Log 就会记录一条 DELETE;当你执行 UPDATE,它就记下修改前的值。像是“后悔药”,在 Rollback 时,Undo Log 进行还原

隔离性

隔离性(Isolation)是数据库最难搞的地方。如果所有事务都排除(Serializable),数据最安全,但用户会等疯掉。为了快,我们必须允许一定程度的“并发”

隔离级别(你对错误的容忍度)

  • RC(Read Committed):读已提交。它解决了“脏读”,但解决不了“这秒读是10块,下秒读20块”的尴尬(不可重复读)
  • RR(Repeatable Read):可重复读。这是 MySQL 的默认级别。它让你在整个事务期间,看到同一行数据永远是一样的

MVCC

为什么 MySQL 读写可发并发?靠的就是MVCC(多版本并发控制)

版本链:每条记录背后都有两个隐藏字段:trx_id(最后修改它的事务ID)和 roll_pointer(指向 Undo Log 的指针)。这形成了一个历史版本的链条

Read View(一致性视图)

  • RC 级别下,每次 Select 都会生成一个新的 Read View,所以能看到别人刚提交的修改
  • RR 级别下,整个事务只在第一次 Select 时生成 Read View,之后无论别人怎么改,它都只看这个“快照”

幻读

很多人认为 RR 无法解决“幻读”(即:明明查的时候没有运行,插的时候却提示已存在)。但在 MySQL 的 InnoDB 引擎里,我们通过 Next-Key Locks(间隙锁+行锁) 很大程度上解决了这个问题

posted @ 2026-05-13 15:14  我已有个她  阅读(2)  评论(0)    收藏  举报