赞
踩
目录
为了提高数据库并发能力,首先应该想到的就是多线程,但是多线程带来的线程安全问题又不得不考虑。通常采用加锁解决,但这个锁的粒度和锁策略是至关重要的。MVCC全称MultiVersioned ConcurrencyControl(多版本并发控制),MVCC使用了锁、UndoLog以及ReadView配合来完成这件事情。
MVCC的实现是基于 Undo Log 版本链和 ReadView 来完成的,Undo Log做为回滚的基础,在执行Update或Delete操作时,会将每次操作的上一个版本记录在Undo Log中,每条Undo Log中都记录⼀个叫做 roll_pointer 的引用信息,通过 roll_pointer 就可以将某条数据对应的Undo Log组织成⼀个Undo链,在数据行的头部通过数据行中的 roll_pointer 与Undo Log中的第⼀条日志进行关联,这样就构成一条完整的数据版本链。
每一条被修改的记录都会有一条版本链,体现了这条记录的所有变更,当有事务对这条数据进行修改时,将修改后的数据链接到版本链接的头部。
每条数据的版本链都构造好之后,在查询时具体选择哪个版本呢?这⾥就需要使用 ReadView 结构来实现了,所谓 ReadView 是⼀个内存结构,顾名思义是⼀个视图,在事务使用 select 查询数据时就会构造⼀个ReadView,里面记录了该版本链的一些统计值,这样在后续查询处理时就不用遍历所有版本链了,这些统计值具体包括:
构造好 ReadView 之后需要根据一定的查询规则找到唯一的可用版本,会在UndoLog版本连中找到select查询具体记录版本的链头,从链头开始遍历所有版本,根据四步查找规则,判断每个版本是否符合要求,如果某个版本符合要求则返回该版本数据。
这样从版本链头遍历判断到版本链尾,找到⾸个符合要求的版本即可,就可以实现查询到的结果都是已经提交事务的数据,那么就可以解决脏读问题。
这些机制加上锁就可以实现MySQL的四种隔离性
实现方式
存在问题
事务的 READ UNCOMMITTED 隔离级别不使用独占锁,所以并发性能很高,但是会出现大量的数据安全问题。
比如在事务A中执行了一条 INSERT 语句,在没有执行 COMMIT 的情况下,会在事务B中被读取到,此时如果事务A执行回滚操作,那么事务B中读取到事务A写入的数据将没有意义,这个现象叫做 "脏读"。
注意:
由于 READ UNCOMMITTED 读未提交会出现"脏读"现象,在正常的业务中出现这种问题会产生非常危重后果,所以正常情况下应该避免使用 READ UNCOMMITTED 读未提交这种的隔离级别。
实现方式
存在问题
为了解决脏读问题,可以把事务的隔离级别设置为 READ COMMITTED ,这时事务只能读到了其他事务提交之后的数据,但会出现不可重复读的问题,核心原因就是每次快照读都会构造新的ReadView。
比如事务A先对某条数据进行了查询,之后事务B对这条数据进行了修改,并且提交( COMMIT )事务,事务A再对这条数据进行查询时,得到了事务B修改之后的结果,这导致了事务A在同一个事务中以相同的条件查询得到了不同的值,这个现象要"不可重复读"。
实现方式
存在问题
事务的 REPEATABLE READ 隔离级别是会出现幻读问题的,在 InnoDB 中使用了Next-Key行锁来解决大部分场景下的幻读问题,那么在不加 Next-Key 行锁的情况下会出现什么问题吗?
使用 Next-Key 锁,锁住的是当前索引记录以及索引记录前面的间隙,那么在不加 NextKey 锁的情况下,也就是只对当前修改行加了独占行锁(X),这时记录前的间隙没有被锁定,其他的事务就可以向这个间隙中插入记录,就会导致一个问题如下:
比如事务A查询了一个区间的记录得到结果集A,事务B向这个区间的间隙中写入了⼀条记录,事务A再查询这个区间的结果集时会查到事务B新写入的记录得到结果集B,两次查询的结果集不一致,这个现象就是"幻读“ 。
实现方式
存在问题
所有的更新都是串行操作,效率极低
当理解了不同隔离级别下实现原理与所存在的问题时,可以修改数据库隔离级别进行问题重现,理论与实操结合,相信你会有很大收获。
这里提供一些可能会用到的命令
- # 开启事务
- START TRANSACTION;
- # 提交事务
- commit;
- # 回滚事务
- rollback;
- # 查看全局作用域隔离级别
- SELECT @@GLOBAL.transaction_isolation;
- # 查看会话作用域隔离级别
- SELECT @@SESSION.transaction_isolation;
- # 通过GLOBAL|SESSION分别指定不同作用域下隔离级别
- SET [GLOBAL|SESSION] TRANSACTION ISOLATION LEVEL level|access_mode;
- # 隔离级别level:
- REPEATABLE READ # 可重复读
- READ COMMITTED # 读已提交
- READ UNCOMMITTED # 读未提交
- SERIALIZABLE # 串⾏化
- # 访问模式access_mode:
- READ WRITE # 表⽰事务可以对数据进⾏读写
- READ ONLY # 表⽰事务是只读,不能对数据进⾏读写
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。