打工四年总结的数据库知识点( 八 )


快照读与当前读在可重复读级别中 , 通过MVCC机制 , 虽然让数据变得可重复读 , 但我们读到的数据可能是历史数据 , 是不及时的数据 , 不是数据库当前的数据!这在一些对于数据的时效特别敏感的业务中 , 就很可能出问题 。
对于这种读取历史数据的方式 , 我们叫它快照读 (snapshot read) , 而读取数据库当前版本数据的方式 , 叫当前读 (current read) 。 很显然 , 在MVCC中:
快照读
MVCC 的 SELECT 操作是快照中的数据 , 不需要进行加锁操作 。
select * from table ….;当前读
MVCC 其它会对数据库进行修改的操作(INSERT、UPDATE、DELETE)需要进行加锁操作 , 从而读取最新的数据 。 可以看到 MVCC 并不是完全不用加锁 , 而只是避免了 SELECT 的加锁操作 。
INSERT;UPDATE;DELETE;在进行 SELECT 操作时 , 可以强制指定进行加锁操作 。 以下第一个语句需要加 S 锁 , 第二个需要加 X 锁 。
- select * from table where ? lock in share mode;- select * from table where ? for update;事务的隔离级别实际上都是定义的当前读的级别 , MySQL为了减少锁处理(包括等待其它锁)的时间 , 提升并发能力 , 引入了快照读的概念 , 使得select不用加锁 。 而update、insert这些“当前读”的隔离性 , 就需要通过加锁来实现了 。
锁算法Record Lock锁定一个记录上的索引 , 而不是记录本身 。
如果表没有设置索引 , InnoDB 会自动在主键上创建隐藏的聚簇索引 , 因此 Record Locks 依然可以使用 。
Gap Lock锁定索引之间的间隙 , 但是不包含索引本身 。 例如当一个事务执行以下语句 , 其它事务就不能在 t.c 中插入 15 。
SELECT c FROM t WHERE c BETWEEN 10 and 20 FOR UPDATE;Next-Key Lock它是 Record Locks 和 Gap Locks 的结合 , 不仅锁定一个记录上的索引 , 也锁定索引之间的间隙 。 例如一个索引包含以下值:10, 11, 13, and 20 , 那么就需要锁定以下区间:
(-∞, 10](10, 11](11, 13](13, 20](20, +∞)在 InnoDB 存储引擎中 , SELECT 操作的不可重复读问题通过 MVCC 得到了解决 , 而 UPDATE、DELETE 的不可重复读问题通过 Record Lock 解决 , INSERT 的不可重复读问题是通过 Next-Key Lock(Record Lock + Gap Lock)解决的 。
锁问题脏读脏读指的是不同事务下 , 当前事务可以读取到另外事务未提交的数据 。
例如:
T1 修改一个数据 , T2 随后读取这个数据 。 如果 T1 撤销了这次修改 , 那么 T2 读取的数据是脏数据 。
打工四年总结的数据库知识点文章插图
不可重复读不可重复读指的是同一事务内多次读取同一数据集合 , 读取到的数据是不一样的情况 。
例如:
T2 读取一个数据 , T1 对该数据做了修改 。 如果 T2 再次读取这个数据 , 此时读取的结果和第一次读取的结果不同 。
打工四年总结的数据库知识点文章插图
在 InnoDB 存储引擎中 , SELECT 操作的不可重复读问题通过 MVCC 得到了解决 , 而 UPDATE、DELETE 的不可重复读问题是通过 Record Lock 解决的 , INSERT 的不可重复读问题是通过 Next-Key Lock(Record Lock + Gap Lock)解决的 。
Phantom Proble(幻影读)The so-called phantom problem occurs within a transaction when the same query produces different sets of rows at different times. For example, if a SELECT is executed twice, but returns a row the second time that was not returned the first time, the row is a “phantom” row.