@@ -2135,7 +2135,7 @@ undo log 是采用段 (segment) 的方式来记录,每个 undo 操作在记录
21352135
21362136rollback segment 称为回滚段,每个回滚段中有 1024 个 undo log segment
21372137
2138- * 在以前老版本,只支持1个 rollback segment,只能记录 1024 个 undo log segment
2138+ * 在以前老版本,只支持 1 个 rollback segment,只能记录 1024 个 undo log segment
21392139* MySQL5.5 开始支持 128 个 rollback segment,支持 128* 1024 个 undo 操作
21402140
21412141
@@ -2168,7 +2168,7 @@ rollback segment 称为回滚段,每个回滚段中有 1024 个 undo log segme
21682168
21692169* 严格的隔离性,对应了事务隔离级别中的 serializable,实际应用中对性能考虑很少使用可串行化
21702170
2171- * 与原子性、持久性侧重于研究事务本身不同,隔离性研究的是不同事务之间的相互影响
2171+ * 与原子性、持久性侧重于研究事务本身不同,隔离性研究的是 ** 不同事务 ** 之间的相互影响
21722172
21732173隔离性让并发情形下的事务之间互不干扰:
21742174
@@ -2254,18 +2254,18 @@ MySQL中还存在 binlog(二进制日志) 也可以记录写操作并用于数
22542254| ---------------- | -------- | ---------------------- | ------------------- |
22552255| read uncommitted | 读未提交 | 脏读、不可重复读、幻读 | |
22562256| read committed | 读已提交 | 不可重复读、幻读 | Oracle / SQL Server |
2257- | repeatable read | 可重复读 | 幻读 | MySQL(避免幻读) |
2257+ | repeatable read | 可重复读 | 幻读 | MySQL |
22582258| serializable | 串行化 | 无 | |
22592259
22602260一般来说,隔离级别越低,系统开销越低,可支持的并发越高,但隔离性也越差
22612261
2262- * 丢失更新 (Lost Update):当两个或多个事务选择同一行,最初的事务修改的值,被后面事务修改的值覆盖,所有的隔离级别都可以避免丢失更新
2262+ * 丢失更新 (Lost Update):当两个或多个事务选择同一行,最初的事务修改的值,被后面事务修改的值覆盖,所有的隔离级别都可以避免丢失更新(行锁)
22632263
22642264* 脏读 (Dirty Reads):在事务中先后两次读取同一个数据,两次读取的结果不一样,原因是在一个事务处理过程中读取了另一个** 未提交** 的事务中的数据
22652265
22662266* 不可重复读 (Non-Repeatable Reads):在事务中先后两次读取同一个数据,两次读取的结果不一样,原因是在一个事务处理过程中读取了另一个事务中修改并** 已提交** 的数据
22672267
2268- > 可重复读的意思是不管读几次,结果都一样,可以重复的读
2268+ > 可重复读的意思是不管读几次,结果都一样,可以重复的读,可以理解为快照读,要读的数据集不会发生变化
22692269
22702270* 幻读 (Phantom Reads):在事务中按某个条件先后两次查询数据库,两次查询结果的数量不同,** 数据条目** 发生了变化。比如查询某数据不存在,准备插入此记录,但执行插入时发现此记录已存在,无法插入;或查询某数据不存在,执行delete删除,却发现删除成功
22712271
@@ -2372,18 +2372,18 @@ undo log 主要分为两种:
23722372
23732373* update undo log:事务在进行 update 或 delete 时产生的 undo log,在事务回滚时需要,在快照读时也需要。不能随意删除,只有在快速读或事务回滚不涉及该日志时,对应的日志才会被 purge 线程统一清除
23742374
2375- 每次对数据库记录进行改动,都会将旧值放到一条undo日志中 ,算是该记录的一个旧版本,随着更新次数的增多,所有的版本都会被 roll_pointer 属性连接成一个链表,把这个链表称之为** 版本链** ,版本链的头节点就是当前记录最新的值,链尾就是最早的旧记录
2375+ 每次对数据库记录进行改动,都会将旧值放到一条 undo 日志中 ,算是该记录的一个旧版本,随着更新次数的增多,所有的版本都会被 roll_pointer 属性连接成一个链表,把这个链表称之为** 版本链** ,版本链的头节点就是当前记录最新的值,链尾就是最早的旧记录
23762376
23772377<img src =" https://gitee.com/seazean/images/raw/master/DB/MySQL-MVCC版本链.png " style =" zoom : 80% ;" />
23782378
23792379* 有个事务插入 persion 表一条新记录,name 为 Jerry,age 为 24
23802380
2381- * 事务1修改该行数据时 ,数据库会先对该行加排他锁,然后先把该行数据拷贝到 undo log 中作为旧记录,拷贝完毕后修改该行 name 为Tom,并且修改隐藏字段的事务ID为当前事务1的ID (默认为 1 之后递增),回滚指针指向拷贝到 undo log 的副本记录,事务提交后,释放锁
2381+ * 事务 1 修改该行数据时 ,数据库会先对该行加排他锁,然后先把该行数据拷贝到 undo log 中作为旧记录,拷贝完毕后修改该行 name 为 Tom,并且修改隐藏字段的事务 ID 为当前事务 1 的 ID (默认为 1 之后递增),回滚指针指向拷贝到 undo log 的副本记录,事务提交后,释放锁
23822382* 以此类推
23832383
23842384purge 线程:
23852385
2386- 为了实现 InnoDB 的 MVCC 机制,更新或者删除操作都只是设置一下老记录的 deleted_bit,并不真正将过时的记录删除,为了节省磁盘空间,InnoDB 有专门的 purge 线程来清理 deleted_bit 为true的记录 ,purge 线程维护了一个 Read view(这个 Read view 相当于系统中最老活跃事务的 Read view),如果某个记录的 deleted_bit 为true ,并且 DB_TRX_ID 相对于 purge 线程的 Read view 可见,那么这条记录一定是可以被安全清除的
2386+ 为了实现 InnoDB 的 MVCC 机制,更新或者删除操作都只是设置一下老记录的 deleted_bit,并不真正将过时的记录删除,为了节省磁盘空间,InnoDB 有专门的 purge 线程来清理 deleted_bit 为 true 的记录 ,purge 线程维护了一个 Read view(这个 Read view 相当于系统中最老活跃事务的 Read view),如果某个记录的 deleted_bit 为 true ,并且 DB_TRX_ID 相对于 purge 线程的 Read view 可见,那么这条记录一定是可以被安全清除的
23872387
23882388
23892389
@@ -2393,25 +2393,25 @@ purge 线程:
23932393
23942394##### 读视图
23952395
2396- Read View 是事务进行快照读操作时产生的读视图,该事务执行快照读的那一刻会生成数据库系统当前的一个快照,记录并维护系统当前活跃事务的ID ,用来做可见性判断,根据视图判断当前事务能够看到哪个版本的数据
2396+ Read View 是事务进行快照读操作时产生的读视图,该事务执行快照读的那一刻会生成数据库系统当前的一个快照,记录并维护系统当前活跃事务的 ID ,用来做可见性判断,根据视图判断当前事务能够看到哪个版本的数据
23972397
2398- 工作流程:将版本链的头节点的事务ID(最新数据事务ID)DB_TRX_ID 取出来,与系统当前活跃事务的 ID 对比,如果 DB_TRX_ID 不符合可见性,那就通过 DB_ROLL_PTR 回滚指针去取出 undo log 中的下一个 DB_TRX_ID 再比较,直到找到满足特定条件的 DB_TRX_ID,该事务 ID 所在的旧记录就是当前事务能看见的最新的记录
2398+ 工作流程:将版本链的头节点的事务ID(最新数据事务ID)DB_TRX_ID 取出来,与系统当前活跃事务的 ID 对比,如果 DB_TRX_ID 不符合可见性,通过 DB_ROLL_PTR 回滚指针去取出 undo log 中的下一个 DB_TRX_ID 比较,直到找到最近的满足特定条件的 DB_TRX_ID,该事务 ID 所在的旧记录就是当前事务能看见的最新的记录
23992399
24002400Read View 几个属性:
24012401
24022402- m_ids:生成 Read View 时当前系统中活跃的事务 id 列表
24032403- up_limit_id:生成 Read View 时当前系统中活跃的最小的事务 id,也就是 m_ids 中的最小值
2404- - low_limit_id:生成 Read View 时系统应该分配给下一个事务的 id 值,m_ids 中的最大值加1
2405- - creator_trx_id:生成该 Read View 的事务的事务id,就是判断该id的事务能读到什么数据
2404+ - low_limit_id:生成 Read View 时系统应该分配给下一个事务的 id 值,m_ids 中的最大值加 1
2405+ - creator_trx_id:生成该 Read View 的事务的事务 id,就是判断该 id 的事务能读到什么数据
24062406
2407- creator 创建一个 Read View,进行可见性算法分析:(** 解决了读未提交** )
2407+ creator 创建一个 Read View,进行可见性算法分析:(解决了读未提交)
24082408
24092409* db_trx_id == creator_trx_id:表示这个数据就是当前事务自己生成的,自己生成的数据自己肯定能看见,所以这种情况下此数据对 creator 是可见的
2410- * db_trx_id < up_limit_id:该版本对应的事务 ID 小于 Read view 中的最小活跃事务ID ,则这个事务在当前事务之前就已经被 COMMIT 了,对 creator 可见
2410+ * db_trx_id < up_limit_id:该版本对应的事务 ID 小于 Read view 中的最小活跃事务 ID ,则这个事务在当前事务之前就已经被 COMMIT 了,对 creator 可见
24112411
2412- * db_trx_id >= low_limit_id:该版本对应的事务 ID 大于 Read view 中当前系统的最大事务ID ,则说明该数据是在当前 Read view 创建之后才产生的,对 creator 不可见
2412+ * db_trx_id >= low_limit_id:该版本对应的事务 ID 大于 Read view 中当前系统的最大事务 ID ,则说明该数据是在当前 Read view 创建之后才产生的,对 creator 不可见
24132413* up_limit_id <= db_trx_id < low_limit_id:判断 db_trx_id 是否在活跃事务列表 m_ids 中
2414- * 在列表中,说明该版本对应的事务正在运行,数据不能显示(不能读到未提交的数据)
2414+ * 在列表中,说明该版本对应的事务正在运行,数据不能显示(** 不能读到未提交的数据** )
24152415 * 不在列表中,说明该版本对应的事务已经被提交,数据可以显示
24162416
24172417
@@ -2479,7 +2479,7 @@ RR、RC 生成时机:
24792479解决幻读问题:
24802480
24812481- 快照读:通过 MVCC 来进行控制的,不用加锁,当前事务只生成一次 Read View,外部操作没有影响
2482- - 当前读:通过 next-key 锁(行锁+ 间隙锁)来解决问题
2482+ - 当前读:通过 next-key 锁(行锁 + 间隙锁)来解决问题
24832483
24842484RC、RR 级别下的 InnoDB 快照读区别
24852485
@@ -5895,7 +5895,7 @@ InnoDB 实现了以下两种类型的行锁:
58955895- 共享锁 (S):又称为读锁,简称 S 锁,就是多个事务对于同一数据可以共享一把锁,都能访问到数据,但是只能读不能修改
58965896- 排他锁 (X):又称为写锁,简称 X 锁,就是不能与其他锁并存,如一个事务获取了一个数据行的排他锁,其他事务就不能再获取该行的其他锁,包括共享锁和排他锁,只有获取排他锁的事务是可以对数据读取和修改
58975897
5898- 对于 UPDATE 、DELETE 和 INSERT 语句,InnoDB 会自动给涉及数据集加排他锁 ;对于普通 SELECT 语句,InnoDB 不会加任何锁
5898+ 对于 UPDATE 、DELETE 和 INSERT 语句,InnoDB 会 ** 自动给涉及数据集加排他锁 ** (行锁) ;对于普通 SELECT 语句,不会加任何锁
58995899
59005900锁的兼容性:
59015901
@@ -6052,7 +6052,7 @@ SELECT * FROM table_name WHERE ... FOR UPDATE -- 排他锁
60526052* 唯一索引加锁只有在值存在时才是行锁,值不存在会变成间隙锁,所以范围查询时容易出现间隙锁
60536053* 对于联合索引且是唯一索引,如果 where 条件只包括联合索引的一部分,那么会加间隙锁
60546054
6055- 加锁的基本单位是 next- key lock,该锁是行锁和这条记录前面的 gap lock 的组合,就是行锁加间隙锁。
6055+ 加锁的基本单位是 next- key lock,该锁是行锁和这条记录前面的 gap lock 的组合,就是行锁加间隙锁
60566056
60576057* 加锁遵循前开后闭原则
60586058* 假设有索引值 10 、11 、13 ,那么可能的间隙锁包括:(负无穷,10 ]、(10 ,11 ]、(11 ,13 ]、(13 ,20 ,正无穷),锁住索引 11 会同时对间隙 (10 ,11 ]、(11 ,13 ] 加锁
0 commit comments