事务并发的三种问题:
脏读:读取了别的事务未提交的数据。
不可重复读:你读取过的数据 , 再次读取出来被人改了。
幻读:同一个事务,第1次和第2次读出来的记录数不一样。
隔离级别 | 读未提交 | 读已提交 | 可重复读 | 可串行化 |
| ReadUncommitted | ReadCommitted | REPEATABLE READ | SERIALIZABL |
理论锁 | 写事务阻塞写,但不阻塞读。 | 写事务会阻塞写、读事务,但是读不阻塞写, | 写阻塞读写,读阻塞写(锁所有行) | 读加共享锁,写加排他锁(锁表) |
Mysql实际锁 | 只有写阻塞写 | 只有写阻塞写 | 只有写阻塞写 | 写阻塞读、写, 读阻塞写。 |
可能存在问题 | 脏读、不可重复读、幻读 | 不可重复读、幻读 | 幻读 | 无 |
Mysql实际存在问题 | 脏读、不可重复读、幻读 | 不可重复读、幻读 | 无 | 无 |
[读未提交]
其他事务和非事务都能读取事务A更改的中间数据。
[读已提交]
写并不会阻塞读,只不过读的是当前数据库的值。
[可重复读]
RR级别中,通过以乐观锁为基础的MVCC机制(多版本并发控制),虽然让数据变得可重复读,但我们读到的数据可能是历史数据,不是数据库当前的数据。
一句话总结:在同一个事务内的查询都是事务开始时刻一致的。
[实际情况,RR级别不存在幻读]
mysql的InnoDB通过行锁和GAP锁结合形成的Next-Key锁解决了RR级别时的幻读问题。
[Next-Key锁]
行锁防止别的事务修改或删除,GAP锁防止别的事务新增,行锁和GAP锁结合形成的的Next-Key锁。
[所谓阻塞,是阻塞到什么时候?]
例如:事务A:写(10s)读(1s),B:读(1s)写(2s)。
执行:先后开启A、B事务,然后A执行写;在A执行写的后立即执行B所有操作,B的写会被阻塞。注意是阻塞到A的commit为止,而不是A的写执行完,A在读(1s)时,B的写还会被阻塞。
(名字:Gap锁:间隙锁。Next-Key Lock:后码锁Record Lock:行锁、记录锁。)
1.InnoDB三种行锁定:行锁(Record Lock)、间隙锁(Gap Lock)、Next-Key Lock 。
2.行锁锁定的是索引记录,而不是行数据,也就是说锁定的是key。
3.Next-Key Lock =行锁和间隙锁。
4. InnoDB通过行锁和间隙锁结合形成的Next-Key锁解决了RR级别时的幻读问题。
5. 间隙锁(Gap Lock)一般是针对非唯一索引而言。
6.Gap锁只会阻塞insert操作。(因为最近的索引间隙里是没有数据的,也不可能锁其他操作)
7.锁间隙,是锁的索引的间隙,左闭右开。
8.Next-Key Lock:先加行锁再加间隙锁。
9.可以手动给sql加共享锁或者排它锁。
select * from t1 where b=3 forupdate#加排他锁X
select * from db1.t1 where b=3 lock in share mode;#加共享锁S
10. 使用next-key lock的必备条件:
1.RR级别或以上
2.innodb_locks_unsafe_for_binlog的默认值0没有更改。
3.非唯一索引。
11. 如果更新没走索引,会加表锁。走非唯一索引会加Next-Key Lock。走唯一索引加行锁。解释:索引唯一,InnoDB会把锁降级成Record Lock。
12.
锁按照精度分为:行锁、表锁、意向锁。
https://blog.csdn.net/claram/article/details/54023216(待看)
Mysql加锁详解:http://hedengcheng.com/?p=771
因为如果测试数据较少的话,可能优化器直接走全表扫描,那就导致锁住所有记录,无法模拟出Gap锁。