前言: 在前面的文章中都遗留了锁的问题,事务并发-幻读实验问题3、5该如何解决,事务并发-锁实验(1)中还有哪些锁
FOR UPDATE(排他锁)
执行如下操作:
- session1执行到l1,查看两次select结果,结果为5
- session2到l2处,被session1的for update卡住
- session1执行到l3,会看到session2的阻塞释放并返回结果为6
- session2执行l4,看到结果为7,与逻辑相符,没有幻觉
FOR SHARE(共享锁)
按上图的流程进行实验可发现
- 两事务并发对同一个索引加共享锁时,可同时查询到数据
- session1中的update加排它锁时,被session2的共享锁互斥
- 若在session2的l3处与session1一起执行update语句,出现死锁,session1的排他锁等待session2的共享锁匙放,session2的排他锁等待session1的共享锁释放
- 全程只执行session1的语句,共享锁升级为排它锁
- 将session1中l1和l3处的语句交换位置,先加排它锁再加共享锁,执行到l3后,再执行session2的l2语句,session2被卡住
间歇锁
数据准备
INSERT INTO `db2021`.`payment`(`id`, `money`, `name`) VALUES (1, 5, '张三');
INSERT INTO `db2021`.`payment`(`id`, `money`, `name`) VALUES (2, 5, '4');
INSERT INTO `db2021`.`payment`(`id`, `money`, `name`) VALUES (4, 5, 'bbb');
session1
show VARIABLES like 'autocommit';
show variables like '%transaction_isolation%';
set session transaction isolation level repeatable read;
set autocommit = 0;
start TRANSACTION;
UPDATE payment set money = 5 where id >=1 and id <=4;
COMMIT;
session2
show VARIABLES like 'autocommit';
show variables like '%transaction_isolation%';
set session transaction isolation level repeatable read;
set autocommit = 0;
start TRANSACTION;
-- UPDATE payment set money = 6 where id = 2;
INSERT into payment(id,money,`name`) VALUES(3,7,'7');
COMMIT;
session1执行到update语句,session2开始执行,update或insert都会阻塞,因为session1在区间[1,4]加锁,这样可解决session1的幻读,但无法解决session2的幻读。间歇锁只在repeatable read级别出发。所以repeatable read级别事务并发时,只会有一个session可能会产生幻读
状态锁-表状态锁
当表中的某记录加锁后,会给表设置一个状态--存在记录加锁。当并发事务对表加锁时,会判断表的状态,发现存在记录加锁则事务阻塞,提升性能,不必去遍历索引是否存在锁
show VARIABLES like 'autocommit';
show variables like '%transaction_isolation%';
set session transaction isolation level repeatable read;
set autocommit = 0;
start TRANSACTION;
UPDATE payment set money = 5 where id = 16;
COMMIT;
show VARIABLES like 'autocommit';
show variables like '%transaction_isolation%';
set session transaction isolation level repeatable read;
set autocommit = 0;
start TRANSACTION;
UPDATE payment set name = 'hello';
COMMIT;
结论
- 加for update后在select就卡住,避免幻读。不加for update时在update语句卡住,事务添加排他锁
- 排他锁:排斥其他事务的锁,同一事务的锁不会排斥
- 在同一个事务对同一索引的共享锁可再设置排他锁,此时锁升级为排他锁
- 在同一个事务对同一索引的排他锁可再设置共享锁,但此时锁不会降级为共享锁,仍为排他锁
- 与java锁概念类似,同一线程(事务)获取锁后可重复获取锁,java的锁可升级降级,事务的锁只可升级
问题
-
java锁结构与事务锁结构有什么类似地方,锁队列都是如何设计的