@@ -197,6 +197,10 @@ i++;
197
197
198
198
如果我们需要避免不可重复读的问题的发生,那么我们可以使用** Next-Key Lock算法** (设置事务的隔离级别为` READ REPEATABLE ` )来避免,在MySQL中,不可重复读问题就是Phantom Problem,也就是** 幻像问题** 。
199
199
200
+ #### 幻读
201
+
202
+ 幻读本质上也属于不可重复读的情况,会话 A 读取某个范围的数据,会话 B 在这个范围内** 插入** 新的数据,会话 A 再次读取这个范围的数据,此时读取的结果和和第一次读取的结果不同。
203
+
200
204
#### 丢失更新
201
205
202
206
** 丢失更新:** 指的是一个事务的更新操作会被另外一个事务的更新操作所覆盖,从而导致数据的不一致。在当前数据库的任何隔离级别下都不会导致丢失更新问题,要出现这个问题,在多用户计算机系统环境下有可能出现这种问题。
@@ -233,7 +237,37 @@ i++;
233
237
234
238
![ ] ( http://image.ouyangsihai.cn/Fh1arOgS78BnrjBXKwGw8NSP27uM )
235
239
240
+ ### MVCC 实现原理
241
+
242
+ 在理解 MVCC 的实现原理之前,需要先带大家了解一下 ** 版本链** 。
243
+
244
+ 我们都知道,在 InnoDB 每个事务都有一个唯一的事务 ID(transaction id),该 ID 是在启动一个事务时申请的并且严格顺序递增。
245
+
246
+ 另外,数据表中的每行数据都是有多个版本的,每次事务更新都会生成新的版本,并且把本次事务的 transaction id 赋值给这个数据版本的事务 ID(row trx_id)。
247
+
248
+ 除此之外,还有一个 roll_pointer指针,该指针 ROLL_PTR 把一个数据行的所有快照版本记录连接起来。
249
+
250
+ undo log 的回滚机制也是依靠这个版本链,每次对记录进行改动,都会记录一条undo日志,每条undo日志也都有一个roll_pointer属性(INSERT操作对应的undo日志没有该属性,因为该记录并没有更早的版本),可以将这些undo日志都连起来,串成一个链表,所以现在的情况就像下图一样:
251
+
252
+ ![ ] ( http://image.ouyangsihai.cn/Fidy__nsyaUj1N3MGfGlu1hjbYMM )
253
+
254
+ 有了上面的知识储备,所谓的 MVCC(Multi-Version Concurrency Control ,多版本并发控制)指的就是在使用** 读已提交(READ COMMITTD)** 、** 可重复读(REPEATABLE READ)** 这两种隔离级别的事务在执行普通的 SELECT 操作时访问记录的版本链的过程,这样子可以使不同事务的读-写、写-读操作并发执行,从而提升系统性能。
255
+
256
+ 这两个隔离级别的一个很大不同就是:生成 ReadView 的时机不同,READ COMMITTD 在每一次进行普通 SELECT 操作前都会生成一个 ReadView,而 REPEATABLE READ 只在第一次进行普通 SELECT 操作前生成一个ReadView,数据的可重复读其实就是 ReadView 的重复使用。
236
257
258
+ #### ** ReadView**
259
+
260
+ MVCC 维护了一个 ReadView 结构,主要包含了当前系统未提交的事务列表 TRX_IDs {TRX_ID_1, TRX_ID_2, ...},还有该列表的最小值 TRX_ID_MIN 和 TRX_ID_MAX。
261
+
262
+ 在进行 SELECT 操作时,根据数据行快照的 TRX_ID 与 TRX_ID_MIN 和 TRX_ID_MAX 之间的关系,从而判断数据行快照是否可以使用:
263
+
264
+ - TRX_ID < TRX_ID_MIN,表示该数据行快照时在当前所有未提交事务之前进行更改的,因此可以使用。
265
+ - TRX_ID > TRX_ID_MAX,表示该数据行快照是在事务启动之后被更改的,因此不可使用。
266
+ - TRX_ID_MIN <= TRX_ID <= TRX_ID_MAX,需要根据隔离级别再进行判断:
267
+ - 提交读:如果 TRX_ID 在 TRX_IDs 列表中,表示该数据行快照对应的事务还未提交,则该快照不可使用。否则表示已经提交,可以使用。
268
+ - 可重复读:都不可以使用。因为如果可以使用的话,那么其它事务也可以读到这个数据行快照并进行修改,那么当前事务再去读这个数据行得到的值就会发生改变,也就是出现了不可重复读问题。
269
+
270
+ 在数据行快照不可使用的情况下,需要沿着 Undo Log 的回滚指针 ROLL_PTR 找到下一个快照,再进行上面的判断。
237
271
### 锁相关
238
272
239
273
> 数据库中锁机制,说说数据库中锁的类型
@@ -258,10 +292,17 @@ InnoDB存储引擎中存在着不同类型的锁,下面一一介绍一下。
258
292
259
293
为了允许行锁和表锁共存,实现多粒度锁机制,InnoDB存储引擎支持一种额外的锁方式,就称为** 意向锁** ,意向锁在 InnoDB 中是** 表级锁** ,意向锁分为:
260
294
261
-
262
295
- 意向共享锁:表达一个事务想要获取一张表中某几行的共享锁。
263
296
- 意向排他锁:表达一个事务想要获取一张表中某几行的排他锁。
264
297
298
+ 在存在行级锁和表级锁的情况下,事务 T 想要对表 A 加 X 锁,就需要先检测是否有其它事务对表 A 或者表 A 中的任意一行加了锁,那么就需要对表 A 的每一行都检测一次,这是非常耗时的。
299
+
300
+ 意向锁在原来的 X/S 锁之上引入了 IX/IS,IX/IS 都是表锁,用来表示一个事务想要在表中的某个数据行上加 X 锁或 S 锁。有以下两个规定:
301
+
302
+ - 一个事务在获得某个数据行对象的 S 锁之前,必须先获得表的 IS 锁或者更强的锁;
303
+ - 一个事务在获得某个数据行对象的 X 锁之前,必须先获得表的 IX 锁。
304
+
305
+ 通过引入意向锁,事务 T 想要对表 A 加 X 锁,只需要先检测是否有其它事务对表 A 加了 X/IX/S/IS 锁,如果加了就表示有其它事务正在使用这个表或者表中某一行的锁,因此事务 T 加 X 锁失败。
265
306
266
307
另外,这些锁之间的并不是一定可以共存的,有些锁之间是不兼容的,所谓** 兼容性** 就是指事务 A 获得一个某行某种锁之后,事务 B 同样的在这个行上尝试获取某种锁,如果能立即获取,则称锁兼容,反之叫冲突。
267
308
@@ -276,6 +317,8 @@ InnoDB存储引擎中存在着不同类型的锁,下面一一介绍一下。
276
317
277
318
![ ] ( http://image.ouyangsihai.cn/Fgf-Pg6JPVJ7CmPyrdcow_5q-VZm )
278
319
320
+ ** 注意:** 任意 IS/IX 锁之间都是兼容的,因为它们只表示想要对表加锁,而不是真正加锁。
321
+
279
322
> MySQL中锁的粒度
280
323
281
324
在数据库中,锁的粒度的不同可以分为表锁、页锁、行锁,这些锁的粒度之间也是会发生升级的,** 锁升级** 的意思就是讲当前锁的粒度降低,数据库可以把一个表的1000个行锁升级为一个页锁,或者将页锁升级为表锁,下面分别介绍一下这三种锁的粒度(参考自博客:https://blog.csdn.net/baolingye/article/details/102506072)。
@@ -696,5 +739,45 @@ MyISAM引擎会把表自增主键的最大id记录到数据文件中,做了持
696
739
697
740
关系型数据库的优势在于支持更加复杂的sql操作、事务支持和使用表结构更加易于维护。
698
741
742
+ > binlog、redo log和undo log
743
+
744
+ redo log(重做日志)是InnoDB存储引擎独有的,它让MySQL拥有了崩溃恢复能力。
745
+
746
+ 比如 MySQL 实例挂了或宕机了,重启时,InnoDB存储引擎会使用redo log恢复数据,保证数据的** 持久性与完整性** 。
747
+
748
+ redo log 记录的是数据的物理变化。
749
+
750
+
751
+ binlog 记录了数据库表结构和表数据变更,比如update/delete/insert/truncate/create。它不会记录select(因为这没有对表没有进行变更),存储着每条变更的SQL语句(当然从下面的图看来看,不止SQL,还有XID「事务Id」等等)。
752
+
753
+ 主要有两个作用:** 复制和恢复数据**
754
+
755
+ - MySQL在公司使用的时候往往都是一主多从结构的,从服务器需要与主服务器的数据保持一致,这就是通过binlog来实现的
756
+
757
+ - 数据库的数据被干掉了,我们可以通过binlog来对数据进行恢复。
758
+
759
+ undo log主要有两个作用:** 回滚和多版本控制(MVCC)**
760
+
761
+ 在数据修改的时候,不仅记录了redo log,还记录undo log,如果因为某些原因导致事务失败或回滚了,可以用undo log进行回滚
762
+
763
+ undo log 主要存储的也是** 逻辑日志** ,比如我们要insert一条数据了,那undo log会记录的一条对应的delete日志。我们要update一条记录时,它会记录一条对应相反的update记录。
764
+
765
+ 这也应该容易理解,毕竟回滚嘛,跟需要修改的操作相反就好,这样就能达到回滚的目的。因为支持回滚操作,所以我们就能保证** 原子性** 。
766
+
767
+ > mysql 优化思路
768
+
769
+ https://mp.weixin.qq.com/s/jtuLb8uAIHJNvNpwcIZfpA
770
+
771
+ https://www.cnblogs.com/jay-huaxiao/p/12995510.html
772
+
773
+ > mysql 语法和复杂语句练习题
774
+
775
+ - 常用语法
776
+
777
+ https://www.jb51.net/article/156898.htm
778
+ www.cyc2018.xyz/算法/基础/算法 - 排序.html
699
779
780
+ - 练习题
700
781
782
+ https://www.jianshu.com/p/476b52ee4f1b
783
+ www.cyc2018.xyz/算法/基础/算法 - 排序.html
0 commit comments