数据库锁
https://www.cnblogs.com/liuqing576598117/p/10366233.html
查看正在锁的事物:
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS
查看等待锁的事物:
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS
show processlist
查询表被锁进程
(1)共享锁(读保护,读的时候不能写)
T1: select * from table (执行N久)
T2: update table set column1='hello'
过程:
T1运行 (加共享锁)
T2运行
If T1 还没执行完
T2等......
else
锁被释放
T2执行
endif
T2之所以要等,是因为T2在执行update前,试图对table表加一个排他锁,而数据库规定同一资源上不能同时共存共享锁和排他锁。所以T2必须等T1。
(2)更新锁(Update lock)(只锁更新,写锁)
T1: select * from table(updlock) (加更新锁)
update table set column1='hello'
T2: select * from table(updlock)
update table set column1='world'
T3: select * from table
T1执行select,加更新锁。
T2运行,读的时候准备加更新锁,但发现已经有一个更新锁在那儿了,只好等T1更新完再select。
T3无影响直接读。
(3)排他锁(独占锁,Exclusive Locks)
T1: update table set column1='hello' where id<1000
T2: update table set column1='world' where id>1000
假设T1先达,T2随后至,这个过程中T1会对id<1000的记录施加排他锁.但不会阻塞T2的update,因为位置相互独立。
(4)意向锁(Intent Locks)
T1: select * from table (xlock) where id=10 --意思是对id=10这一行强加排他锁
T2: select * from table (tablock) --意思是要加表级锁
假设T1先执行,T2后执行,T2执行时,欲加表锁,为判断是否可以加表锁,数据库系统要逐条判断table表每行记录是否已有排他锁,如果发现其中一行已经有排他锁了,就不允许再加表锁了。只是这样逐条判断效率太低了。
实际上,数据库系统不是这样工作的。当T1的select执行时,系统对表table的id=10的这一行加了排他锁,还同时悄悄的对整个表加了意向排他锁(IX),当T2执行表锁时,只需要看到这个表已经有意向排他锁存在,就直接等待,而不需要逐条检查资源了。
(5)计划锁(Schema Locks)
alter table..(加schema locks,称之为Schema modification (Sch-M) locks)
DDL语句都会加Sch-M锁,该锁不允许任何其它session连接该表。连都连不了这个表了,当然更不用说想对该表执行什么sql语句了。
(6) 间隙锁
锁范围,阻止在区间插入新的数据,防止幻读。往往针对非唯一索引。
触发条件:范围查询并且查询未命中记录,查询条件必须命中索引、间隙锁只会出现在REPEATABLE_READ(重复读)的事务级别中。
(7) 临键锁
总结来说它就是记录锁和间隙锁的组合,临键锁会把查询出来的记录锁住,同时也会把该范围查询内的所有间隙空间也会锁住,再之它会把相邻的下一个区间也会锁住。
触发条件:范围查询并命中,查询命中了索引。
- 如果检测到死锁怎么办?
可以强制某个事务回滚,释放掉锁。
举例:死锁发生的场景
事务A | 事务B |
---|---|
delete from T1 where id=1 | |
update T2 set xxx where id=5 | |
update T2 set where id=5 | |
delete from T1 where id=1 | |
commit | commit |