Transaction Isolation in Innodb
事务的一些隔离问题
事务的加锁级别
说到烂了
- Read Uncommitted 读未提交,只防止脏写(其实脏写只是写并发的一个特例而已,还可能有更新丢失这种情况),不防止脏读,这个级别他喵 的就等于没有隔离; 但是注意这种对于一些sum,count操作其实是有用的,只不过我们日常少用;
- Read Committed
很多数据库默认就是这个级别,防止单条记录(读取到)的脏读,但是对于批量范围操作就力不从心,即不能防止幻读 e.g:
- Repeatable Read
在Read Commited的基础上使用快照来隔离不同版本,保证了单条记录加锁以及范围读取的加锁,新的满足查询条件的记录不能够插入,可以解决幻读 (这里指得是只读查询时的,对于读-写事务来讲,还是可能会有写倾斜),幻读指的就是同一个事务中,连续两次当前读得到了两个完全相同(一般有返回多条)的记录; 如果索引(非唯一)的情况下,有Repeatable Read在这两次之间就又加了一个细化的锁(Gap Lock)保证这两次读之间不会插入新的提交值详情可以看下面的Gap锁
同Read Commited一样的是都有写锁,但是读不加锁,采用保存了多个版本(MVCC)来实现;
有些数据库会直接使用MVCC保存一个已提交的旧版本和一个未提交的新版本来实现Read Commited,虽然未提供完整的快照隔离,这种操作(Read Commited)是对于每一个不同的查询单独创建一个快照,而完整的快照级别隔离则需要对整个事务用一个快照进行
- Serilizable 全部操作串行化,并发度下降,不推荐
写事务
-
脏写
-
更新丢失
- 写倾斜
锁与索引的关系
这里会有人问到,加锁的话怎么用索引呢?
- 有一种方案是:索引直接指向数据对象的所有版本,然后使用一些策略过滤掉对当前事务不可见的版本,当后台gc进程决定删除某些旧对象版本时,对应的索引也要删除; 一些数据库会把同一对象的不同版本放在同一个内存页中; 一些有b-tree结构的数据库则使用append/copy-on-write方法,需要更新的时候会创建一个修改副本,copy一些必要的内容,然后让父节点或者递归一直到root的节点都指向新创建的节点,
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!