https://tech.meituan.com/2014/08/20/innodb-lock.html
查看当前会话的事务隔离级别
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation|
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set (0.03 sec)
查看全局事务隔离级别
mysql> select @@global.tx_isolation;
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| REPEATABLE-READ|
+-----------------------+
1 row in set (0.04 sec)
四种bug:
(1)脏读:(不同事务间,快照解决)例:
insert into T values (4, '牛D');
,然后没commit。一个事务内的
SELECT
读取到的数据是另一个事务未commit的数据。(数据库只修改了缓存没修改外存,但是不同事务的select会读到之前另一事务update的数据)(2)不可重复读:(同一事务,第一次select后的数据上行级锁)例:同一个事务内,对同一行的两个相同的查询却返回了不同数据(因为中间有其他事务修改/删除了值并且提交成功)
(3)幻读:(可以加间隙锁解决)例:某个事务在读取某个范围的数据,但是另一个事务又向这个范围的数据去insert数据,导致多次读取的时候,数据的行数不一致。(delete是不可重复读,因为读的内容少了,对同一行的查询出现了不一致,insert对同一行的查询没有不一致)
隔离级别 | 脏读 | 不可重复读 | 幻读(Phantom Read) |
---|---|---|---|
未提交读(Read uncommitted) | 可能 | 可能 | 可能 |
已提交读(Read committed) | 不可能 | 可能 | 可能 |
可重复读(Repeatable read) | 不可能 | 不可能 | 可能 |
可串行化(Serializable) | 不可能 | 不可能 | 不可能 |
- 可重复读的目标:
(1)版本未提交,不可见;
(2)版本已提交,但是是在快照创建后提交的,不可见;
(3)版本已提交,而且是在快照创建前提交的,可见。
InnoDB事务隔离级别:
set session transaction isolation level repeatable read;
// 设置当前会话隔离级别
- READ UNCIMMITTED(未提交读)
文章图片
image.png
- READ COMMITTED(提交读)
为什么提交读,未提交读都没有查询加锁,但是却能够避免脏读呢?
这就要说道另一个机制-快照(snapshot)(读取比该事务早的最后一次提交值)假设当A开启了事务,然后没有执行任何操作,这时候B insert了一条数据然后commit,这时候A执行 select,那么返回的数据中就会有B添加的那条数据。之后无论再有其他事务commit都没有关系,因为快照已经生成了,后面的select都是根据快照来的。
- 假设没有“快照读”,那么当一个更新的事务没有提交时,另一个对更新数据进行查询的事务会因为无法查询而被阻塞,这种情况下,并发能力就相当的差。
- 而“快照读”就可以完成高并发的查询,不过,“读提交”只能避免
脏读
,并不能避免“不可重复读”和“幻读”。
类型 | 语句 |
---|---|
快照读 | select xxx from xxx |
当前读 | (1)select xxx from xxx for update (2) select xxx from xxx lock in share mode (3) insert/delete/update ... |
select * from table where ? lock in share mode;
select * from table where ? for update;
- select ... for update 会让innodb对查询结果中的每一行数据都添加排他锁,其他线程对该记录的更新与删除操作都会阻塞。(必须开启事务)
- Read Committed隔离级别:每次select都生成一个快照读。
- 快照读的实现方式:undolog和多版本并发控制MVCC
- REPEATABLE READ(可重复读)
不可重复读
,但却避免不了“幻读”,因为幻读是由于“插入操作(INSERT)”而产生的,而不是更新(UPDATE)文章图片
image.png
- 在RR隔离级别下,当事务第一次进行快照读,仅此一次创建read-view视图。
- RR隔离级别采用Next-key Lock(间隙锁) 来解决幻读问题。因此 RR 下面 幻读,可重复读,脏读 三者都不会发生。
- SERIALIZABLE(可串行化)
文章图片
image.png
示例
文章图片
image.png (1)如果事务 B 的隔离级别是读未提交(RU),那么两次读取均读取到 x 的最新值,即 20。
(2)如果事务 B 的隔离级别是读已提交(RC),那么第一次读取到旧值 10,第二次因为事务 A 已经提交,则读取到新值 20。
(3)如果事务 B 的隔离级别是可重复读或者串行(RR,S),则两次均读到旧值 10,不论事务 A 是否已经提交。