mysql InnoDB的行锁
InnoDB 存储引擎锁类型主要记住下面两句话就够了:
事务本事(自事务)不存在任何隔离性。
1) 读写锁,实现读读并发。 2) 一致性非锁定读( MVCC ),实现读写并发。
对于mysql InnoDB引擎(一个事务内既可以获取共享锁,同时可以获取排他锁。):
select 默认不加锁,快照读,不受其他事务锁的限制。
select ...for update 加排他锁,(我要读取最新已提交的数据且准备修改,防止在我读取的过程中,其他事务修改)
select ... lock in share mode加共享锁,(我要读取最新已提交的数据但不准备修改【因为很容易出现死锁】,防止在我读取的过程中,其他事务修改)
时间 |
会话 A |
会话 B |
1 |
begin |
|
2 |
select * from t where id=3 lock in share mode; 获得了 S 锁 |
|
3 |
begin |
|
4 |
select * from t where id=3 lock in share mode; 获得了 S 锁 |
|
5 |
update t set name='baiyadong' where id = 3; 等待会话 B 释放 S 锁 |
|
6 |
update t set name='baiyadong' where id = 3; 检测到死锁,会话 B 回滚 |
|
7 |
执行成功 |
一个事务获取了共享锁,其他事务可以获取共享锁,不能获取排他锁。一个事务加共享锁,可以对该条记录进行读写。两个回话都加共享锁,均可以对该条记录进行读,都无法写。
update,delete,insert默认加上排他锁。
一个事务T对数据A加上排他锁后,既可读又可写,其他事务不能再对A加任任何类型的封锁。
一条记录不管是被加排它锁还是共享锁,其它select默认都可以读取执行。
在MVCC并发控制中,读操作可以分成两类:快照读 (snapshot read)与当前读 (current read)。快照读,读取的是记录的可见版本 (有可能是历史版本),不用加锁。当前读,读取的是记录的最新版本,并且,当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条记录。
当前读:每次读都加锁,不允许其他事务对数据进行修改。比如update,delete, select for update ,select in share mode.读的是最新数据(如果其他事务有更新、删除、插入未提交,则该操作阻塞,直至对方事务提交。)。也叫一致性锁定读。
快照读:select读的是历史版本。就是通过mvcc实现的。也就一致性非锁定读。
隔离级别是如何实现的?mvcc,多版本并发控制
RU :读mvcc版本链中的最新数据。
RC:mvcc读取规则。
RR:mvcc读取规则。
Serializable: 普通的select都加锁,完全串行化了,没有 MVCC。
InnoDB 存储引擎如何利用锁实现四种事务隔离级别
按照 SQL92 标准, InnoDB 使用不同的锁策略实现了四种不同事务隔离级别。
未提交读 READ-UNCOMMITTED |
select 语句不加锁,会出现脏读。 隔离性最差,并发最高 |
串行化 SERIALIZABLE |
select 语句隐式转换为 select … in share mode ,与 X 锁互斥。 一致性最好,并发最差,如果有未提交的修改,所有读取这些行的 select 都会被阻塞,没有 MVCC。 |
可重复读 REPEATABLE-READ |
普通 select 是 MVCC 。 锁定读 /update/delete 使用 Record Lock 和 Next-Key Lock ,防止幻影记录出现。 InnoDB 默认的隔离级别。 |
提交读 READ-COMMITTED |
普通 select 是 MVCC 。 锁定读 /update/delete 使用 Record Lock ,可能出现不可重复读。
|
MySQL 存储引擎 InnoDB 隔离级别 RR 解决了幻读问题。