从事务的隔离级别谈起众所周知 , 事务有四大特性 , 简称ACID:原子性、一致性、隔离性、持久性 。
对于隔离性 , 简单来说就是多个事务之间是彼此隔离的 , 互不影响 。但想要做到完全的互不影响是很难的 , 因为数据的强一致性 , 很多时候需要牺牲性能去达成 。比如如果我们能接受事务的串行执行 , 那一定是互不影响的 。然而现实是 , MySQL作为一个数据库 , 必然是要支持一定程度的并行执行的 , 也就是多个事务同时去执行 。
?如果多个事务同时并行执行 , 在没有隔离的情况 , 可能会发生脏读、不可重复读、幻读的问题 。
凡并行程序 , 往往是在性能和数据一致性上做取舍 。较好的解决方案要么是最终一致 , 要么是尽量缩小串行执行的范围 。
?
案例数据(demo表):
id(主键) c(普通索引) d(无索引) 5 5 5 10 10 10 15 15 15 20 20 20 25 25 25
「脏读」
一个事务读取了另一个事务未提交的数据 。
文章插图
脏读
「不可重复读」
一个事务读取同一行数据 , 多次读取结果不同 。
文章插图
不可重复读
「幻读」
一个事务读取到了别的事务插入的数据 。
文章插图
幻读
但InnoDB因为使用了MVCC , 读取的是“快照”版本 , 有一些不同 , 但如果不上锁 , 同样可能会有幻读问题 。
文章插图
InnoDB的幻读
事务用了四种不同的隔离级别用来解决这些问题 。
- Read uncommitted(未提交读)
- Read Committed(已提交读 , 简称RC)
- Repeatable Reads(可重复读 , 简称RR)
- Serializable(串行化)
隔离级别 脏读 不可重复读 幻读 Read uncommitted 是 是 是 Read Committed 是 是 Repeatable Reads 是 Serializable
?无锁思想:MVCCMVCC即“多版本并发控制” , 但是它在很多情况下避免了加锁操作 , 因此开销更低 。
但InnoDB有些许不同 , InnoDB默认的隔离级别是RR , 但是通过MVCC和间隙锁来一定程度上的解决了幻读的问题 。这也是我们今天这篇文章后面会详细介绍的 。
?
主流的关系型数据库都实现了MVCC , 但实现机制各有不同 。实际上MVCC也没有一个统一的标准 。但大都实现了非阻塞的读操作 , 写操作也只是锁定必要的行 。本文以下内容所说的MVCC都指的是InnoDB实现的MVCC 。
在Mysql的InnoDB引擎 , 是通过给每行记录后面保存两个隐藏的列来实现的 。一个是保存行的创建时间 , 另一个保存了行的过期时间(或删除时间) 。
?每次开启一个事务 , 系统版本号都会递增 。事务开始时 , 系统版本号会作为事务的版本号 , 用来和查询到的行的版本号进行比较 。
实际上存储的并不是实际的一个时间戳 , 而是“系统版本号” 。
?
MVCC只在REPEATABLE READ和READ COMMITTED两个隔离级别下工作 , 其它两个隔离级别不能工作 。因为READ UNCOMMITTED总是读取最新的数据行 , 而不是符合当前事务版本的数据行 。而SERIALIZABLE则会对所有读取的行都加锁 。
在MySQL中 , 正常的SELECT语句 , 后面不加FOR UPDATE和LOCK IN SHARE MODE的 , 就是用的MVCC去读 。
?InnoDB行锁的概念InnoDB的行锁(也称为临键锁) Next-Key Locks , 「是MySQL对外暴露的锁的基本单位 , 它会智能选择记录锁或间隙锁 , 锁住一行或多行或一个间隙」 。而记录锁又分为共享锁和排他锁 , 间隙锁的概念下面有一个插入意向锁 。这些锁的关系大概是这样:
MVCC和我们在应用层面去实现的“乐观锁”有一样的思想:用版本号 , 在尽量无锁的情况下实现一定程度的一致性 。
?
推荐阅读
- 清朝的刑法有什么 清朝创立的刑罚
- 使用spring cache让我的接口性能瞬间提升了100倍
- 明朝时,腊八粥是皇帝在腊八节赏赐群臣的神圣食物 腊八粥与明朝皇帝谁有关
- 宋朝官员脖子上戴的白圈圈是什么? 宋代官服脖子上的圈
- 全栈工程师眼中的HTTP
- 何为正宗的金骏眉,金骏眉的功效
- 敬茶体现个人的修养,高桥银峰的茶艺步骤
- 花砖茶的加工方法,花砖茶的制作
- 喝茶的饮食禁忌,有什么禁忌
- 国外程序员经常浏览的技术网站