后端与系统架构图文讲义2309 字

放弃RR选择RC,通过for update理解MySQL锁定机制

·全库 589 / 611

《放弃RR选择RC,通过for update理解MySQL锁定机制》共 5 页、0.2 万字,通篇围绕 MySQL、并发、数据库 展开,归在「后端与系统架构」这一层。

覆盖MySQL并发数据库

适合给 AI 系统搭底座、要管得住的人

目录骨架(4 节)
  1. 放弃 RR 选择 RC,通过 for update 理解 MySQL
  2. 为什么大厂放弃 RR 选择 RC?
  3. 数据库隔离性
  4. 通过 for update 理解 MySQL 锁定机制

原 PDF 已逐页还原成图,共 5 页,这里先放前 3 页,其中 2 页识别出了标题。右侧文字由 OCR 按版面重排,可能有个别错字,以图为准;点图可全屏放大。

本讲义目录 · 3 页
  1. 01放弃 RR 选择 RC,通过 for update 理解 MySQL
  2. 02数据库隔离性
  3. 03为什么大厂放弃 RR 选择 RC?
011 / 3
第 1 页:放弃 RR 选择 RC,通过 for update 理解 MySQL
第 1 页

放弃 RR 选择 RC,通过 for update 理解 MySQL

锁定机制 事务并发问题

修改丢失:两个事务同时修改一个数据,发生了修改覆盖问题。 脏读:是指发生在一个事务读取了另一个事务改写但尚未提交的数据时。如果改写在稍后被回滚了,则 第一个事务获取的数据就是无效的。A 事务读取到了 B 事务尚未提交的数据【原子性】 不可重复读:A 事务执行 2 次相同查询查到了不同数据【一致性】,避免不可重复读需要锁行就行,不可 重复读重点在于 update 和 delete 幻读:是指发生在事务(T1)读取了几行数据,接着另一个并发事务 T2 插入了一些数据时。在随后的查 询中,第一个事务 T1 就会发现多了一些原本不存在的记录。A 事务读取到了 B 事务插入的数据【隔离 性】,避免幻读则需要锁表,幻读的重点在于 insert

通过上图所示,我们了解到,两个事务 T1、T2 同时读入同一数据并修改,T2 提交的结果会破坏或覆盖 T1 提交的结果,导致 T1 的修改丢失。

事务 T2

A 库存=16 件

A 库存=12 件

提交事务

事务 T1

A 库存=16 件

修改: A 库存=10 件

提交事务

结果:A 库存=12 件

022 / 3
第 2 页
第 2 页

数据库隔离性

数据库隔离性

READ UNCOMMITTED:读未提交(RU),脏读,不可重复读、幻读都存在,所有读不加锁,读到的数 据都是最新数据,性能最好,所有写加锁,写完释放 READ COMMITTED:读已提交(RC),解决了脏读,存在不可重复读,幻读问题。oracle 默认隔离级别 REPEATABLE READ:可重复读(RR),解决了脏读,不可重复读,存在幻读。适用 mvcc 技术实现不加锁 的读操作。mysql 默认隔离级别

SERIALIZABLE:串行化(S),全部解决,但是并发效率不高

不可重复读 隔离级别 脏读 读未提交 Read uncommitted 读已提交 X Read committed

可重复读 X Repeatable read 可串行化 X

Serlalizable

RR 与 RC 的区别

在 RR 中,快照会在事务中第一次查询语句执行时生成,只有在本事务中对数据进行更改才会更新快照。 也就是说,如果在本事务中己经执行了一次 select,此时其它事务执行了更改数据的操作并已提交,那么 你在本事务再次 select 时,你是看不到其它事务所做的更改。

事务 A 事务 A 事务流程/事务名

2、begin 开启事务 1、begin 开启事务 4、select(查到 2 条数据) 3、select (查到 2 条数据) select (查到 2 条数据)5、insert/commit 一条数据 6、select (查到 3 条数据) 8、commit 9、select*(查到 3 条数据)

在 RC 中,每次读取都会重新生成一个快照,总是读取行的最新版本。也因此事务中每次 select 也可以看 到其它已 commit 事务所做的修改。

幻读

033 / 3
第 3 页:为什么大厂放弃 RR 选择 RC?
第 3 页

为什么大厂放弃 RR 选择 RC?

事务流程/事务名

在数据库的 RC 这种隔离级别中,还支持半一致读,一条 update 语句,如果 where 条件匹配到的记录已经 加锁,那么 InnoDB 会返回记录最近提交的版本,由 MySQL 上层判断此是否真的需要加锁。

大厂之所以使用 RC,主要原因有二,其一是提升并发,其二是减少死锁。 为什么 RC 要比 RR 并发度好? 因为 RC 在加锁过程中,是不需要添加 Gap Lock (间隙锁)和 Next-Key Lock (临键锁)的,只需要对要修改的 记录添加行级锁就行了。另外,RC 还支持半一致读,可以大大的减少了更新语句时行锁的冲突。对于不 满足更新条件的记录,可以提前释放锁,提升并发度。 为什么 RC 可以减少死锁发生? 因为 RR 会增加 Gap Lock (间隙锁)和 Next-Key Lock (临键锁),这就使得锁的粒度变大了,那么就容易导致 死锁的概率增大(占地太宽了,别人占不到地方了)。

通过 for update 理解 MySQL 锁定机制

  • 数据库的锁,在不同的事务隔离级别下,是采用了不同的机制的。在 MySQL 中,有三种类型的锁,分别 是 Record Lock、Gap Lock 和 Next-Key Lock。 Record Lock 表示记录锁,锁的是索引记录。
  • 共享锁(shared lock)也叫读锁、S 锁,数据被某个事务获取了共享锁之后,还可以被其它事务获 取共享锁,但是不能被其它事务获取排他锁。
  • 排他锁(exclusive Lock)也叫写锁、X 锁,数据被某个事务获取之后就不能被其它事务获取任何锁 举个例子,当一个事务执行了下面这条语句:

mysql > select * from t_test where id = 1 for update;

就是对 ttest 表中主键 id 为 1 的这条记录加上 X 型的记录锁,这样其他事务就无法对这条记录进行修改 了。

事务 A 1、begin 开启事务 3、select (查到 2 条数据)4、select(查到 2 条数据) 7.、Select *(查到 3 条数据))5、insert/commit 一条数据

8、commit 9、select*(查到 3 条数据)

事务 A 2、begin 开启事务

6、select *(查到 3 条数据)

资料里没有你的场景?

把你手上的数据和想解决的那个环节发上来,我们按具体情况回,不复述方法论。

发布需求