知识点整理(九)——mysql的MVCC

知识点整理(九)——mysql的MVCC
逐暗者mysql事务控制
并发事务
并发事务会带来一些问题
脏读
一个事务读取到了另一个事务修改但未提交的数据。不可重复读
一个事务中多次读取同一行记录不一致。幻读
一个事务中多次按相同条件查询,结果不一致。(多了或者少了)
事务隔离级别
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交 | 会发生 | 会发生 | 会发生 |
读已提交 | × | 会发生 | 会发生 |
可重复读 | × | × | 会发生 |
串行化 | × | × | × |
注意mysql的MVCC解决了部分幻读问题(不能解决当前读下的幻读)。
事务并发问题主要是解决读读、读写、写写之间的问题。加排它锁性能太低。使用读写锁能解决读读之间性能问题,但是无法解决读写之间的性能。
MVCC
MVCC使用了Copy On Write的思想。可以支持读读并行,也可以支持读写并行。写写依旧无法并行。
概念
MVCC(Multi Version Concurrency Control)被称为多版本控制。在数据库中为了实现高并发数据访问,对数据进行多版本处理,并通过事务的可见性来保证事务能看到自己应该看到的数据版本。
MVCC最大的好处是读不加锁,读写不冲突,这对读多写少的系统非常重要。现阶段几乎所有关系型数据库都支持MVCC。mysql的MVCC只在读已提交和可重复读2种隔离级别下工作。
实现原理
- 快照读:读取快照版本,普通的select查询,不加锁。
- 当前读:读取记录的最新版本,会加锁。(select for update / lock in share mode/insert/update/delete)
- 事务id:mysql会维护一个全局事务id,每个事务都不一样,自增。
当我们向mysql插入一条记录时,mysql会这么存储。(假设事务1)
{cat_tips_info color=””}
DATA_ROW_ID:隐藏数据ID
DB_TRX_ID:当前事务版本号
DB_ROLL_PT:回滚指针
{/cat_tips_info}
当我们修改这条记录后,mysql会这么存储。(假设事务10)
再修改一下会变成这样。(假设事务15)
mysql会把修改前的记录复制到undo log中,然后修改现有数据,设置当前事务id,设置回滚指针指向之前的记录行。
具体如何实现可重复读呢?
在事务开启时创建readView,之后只按照readView内容进行读取。这样就保证了可以重复读到相同快照内容。(注意事务开启时怎么理解?begin/start transaction时第一个快照读语句,而要立刻开启是start transaction with consistent snapshot)
readView里有哪些东西呢?
- m_ids,当前有哪些事务正在执行,且还没有提交,这些事务的 id 就会存在这里;
- min_trx_id,是指 m_ids 里最小的值;
- max_trx_id,是指m_ids 里最大的值;
- creator_trx_id,每开启一个事务都会生成一个 ReadView,而 creator_trx_id 就是这个开启的事务的 id。
- 如果查到一条记录,其中的DB_TRX_ID小于min_trx_id,那么肯定可以看到这条数据。因为当前事务肯定在活动中,肯定大于min_trx_id,那么本事务开启时这个数据已经提交了。
- 如果查到一条记录,其中的DB_TRX_ID大于max_trx_id,那么这条数据肯定看不到。因为当前事务开启的时候记录所在的事务还没开启。这个时候应该通过回滚指针找到之前版本的记录进行判断。
- 如果查到一条记录,其中的DB_TRX_ID介于min_trx_id和max_trx_id之间,那就看是否在m_ids内,如果在,就表示本事务开始时,记录所在事务还没提交,所以不能看到,反之则能看到。