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(间隙锁+行锁) 很大程度上解决了这个问题
本文来自博客园,作者:我已有个她,转载请注明原文链接:https://www.cnblogs.com/gitgud/p/20032554
浙公网安备 33010602011771号