当前读:update、delete、insert、select …from for update;读取最新的数据
快照度:select查询。根据MVCC读取对应版本数据。
有表student,字段有id、name,现有数据如下:
id | name |
---|---|
1 | 张三 |
2 | 李四 |
有两个事务A和B。操作过程如下:
1.A事务开启:BEGIN
2.A事务查询 :SELECT * FROM student
,查到id为1和2两条数据
3.B事务开启:BEGIN
4.B事务插入数据:INSERT INTO student
(id
, name
) VALUES (3, ‘王五’);
5.B事务提交:COMMIT;
6.A事务再次查询 :SELECT * FROM student
,仍然只能查到id为1和2两条数据(RR可重复读)
7.A事务插入数据:INSERT INTO student
(id
, name
) VALUES (3, ‘王五’);报错:Duplicate entry ‘3’ for key ‘PRIMARY’。产生了幻读。
分析:因为INSERT是当前读,所以会拿到表中最新的数据,而此时id=3的数据已经存在了。所以会插入失败。
如何解决:行锁 + 间隙锁
1.A事务开启:BEGIN
2.A事务查询 :SELECT * FROM student
WHERE id = 3 for update,该语句开启了行锁,会把id = 3这行锁住。
3.B事务开启:BEGIN
4.B事务插入数据:INSERT INTO student
(id
, name
) VALUES (3, ‘王五’); 插入操作会被锁住,直到事务A回滚或提交。
InnoDB的行锁是针对索引加的锁,不是针对记录加的锁。并且该索引不能失效,否则都会从行锁升级为表锁。