Skip to content

Commit 897c4df

Browse files
committed
Update Java Notes
1 parent fccbd53 commit 897c4df

3 files changed

Lines changed: 749 additions & 456 deletions

File tree

DB.md

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2135,7 +2135,7 @@ undo log 是采用段 (segment) 的方式来记录,每个 undo 操作在记录
21352135

21362136
rollback 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

23842384
purge 线程:
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

24002400
Read 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

24842484
RC、RR 级别下的 InnoDB 快照读区别
24852485

@@ -5895,7 +5895,7 @@ InnoDB 实现了以下两种类型的行锁:
58955895
- 共享锁 (S):又称为读锁,简称 S 锁,就是多个事务对于同一数据可以共享一把锁,都能访问到数据,但是只能读不能修改
58965896
- 排他锁 (X):又称为写锁,简称 X 锁,就是不能与其他锁并存,如一个事务获取了一个数据行的排他锁,其他事务就不能再获取该行的其他锁,包括共享锁和排他锁,只有获取排他锁的事务是可以对数据读取和修改
58975897

5898-
对于 UPDATEDELETE 和 INSERT 语句,InnoDB 会自动给涉及数据集加排他锁;对于普通 SELECT 语句,InnoDB 不会加任何锁
5898+
对于 UPDATEDELETE 和 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
* 假设有索引值 101113,那么可能的间隙锁包括:(负无穷,10]、(10,11]、(11,13]、(13,20,正无穷),锁住索引 11 会同时对间隙 (10,11]、(11,13] 加锁

0 commit comments

Comments
 (0)