锁等待和死锁
锁等待:指一个事务过程中产生的锁,其他事务需要等待上一个事务释放它的锁,才能够占用该资源,如果该事务一直不释放,就会持续等待下午,直到超过锁的等待时间,报锁超时的错误。
代码演示:(目前的一张表中,id为主键索引,name创建了唯一索引)
CREATE TABLE `sys_user` (
`id` int(11) NOT NULL,
`name` varchar(60) NOT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name_idex` (`name`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
执行的结果如下,启动两个回话窗口同时更新一条数据的时候出现

另外一个窗口显示

最终提示的错误信息:

死锁:两个以上的线程在执行的过程中,因为资源争夺而造成的一种互相等待的现象,就是所谓的索梓源请求产生了回路现象,即死循环。
如下图中的sql update时,开启了两个回话窗口,会话1中:第一步先去update 获取了一个id=1的资源,
会话2中 第一步也是获取了一个id=2的资源。这个时候会话1y有开始去获取id=2的资源时,出现阻塞。同时会话2去获取id=1的资源时救赎出现异常:DeadLock found where trying to get lock;try restarting transaction

避免死锁的情况:
1 如果不同程序会并发存取多个表,或者设计多行记录时,尽量约定以相同的顺序访问表,可以大大降低死锁的机会。
2 业务中尽量采用小事务,避免使用大事务,要及时提交或回滚事务,可以减少死锁产生的概率。
3 在同一个事务中尽量做到一次锁定所有的资源。
4 对于非常容易产生死锁的业务部分,可以尝试使用升级锁粒度,例如可以升级表锁锁定。
行锁产生的基准:
还是以上面的表为例,还是更新操作。基于name来更新,发现:两个回话在获取两个不同的资源时不会出现任何异常,可以正常执行。


但是一旦把name上的索引删除时,结果就不一样了。最终会提示锁超时,由此可以推断出InnerDB的行锁其实是加在索引上面的。


间隙锁
InnerDB关于事务的隔离级别默认是RR的隔离级别,为了避免幻读现象引入的Gap Lock,但是它只能锁定记录行记录数据的范围,不包含记录本身,即不允许在此范围内插入任何数据。
在会话1中加了共享锁,

会话2中插入一条小于21的数据时出现了失败。这就是间隙锁的作用,但是如果换了一个隔离级别的话间隙锁就失效了。

Next-key-Locks
Next-key-Locks是记录锁和间隙锁的组合当InnerDB扫描索引近路时,会先对选中的索引加记录锁,再对索引记录两边的间隙加上间隙锁。
网友评论