SQL Server有如下几种琐:
-
从类型上来看,可以分为共享锁、排它锁、更新锁
-
从范围来看,可以分为表锁、行锁(记录锁),间隙锁、next-key锁、页锁等。
共享锁:加了S锁的记录,允许其他事务再加S锁,不允许其他事务再加X锁,即会阻止其他用户的写和改。
加锁方式:select…lock in share mode
排他锁:加了X锁的记录,不允许其他事务再加S锁或者X锁。
更新锁:用来预定要对此页施加X锁,它允许其他事务读,但不允许再施加U锁或X锁;当被读取的页将要被更新时,则升级为X锁;U锁一直到事务结束时才能被释放。
例如当两个事物在几行数据行上都使用了共享锁,并同时试图获取独占锁以执行更新操作时,就发生了死锁:都在等待对方释放共享锁而实现独占锁。更新锁的目的是只让一个事物获得更新锁,防止这种情况的发生。
意向锁:意向锁的存在是为了协调行锁和表锁的关系,支持多粒度(表锁与行锁)的锁并存,意向锁是表锁。
例子:事务A修改user表的记录r,会给记录r上一把行级的排他锁(X),同时会给user表上一把意向排他锁(IX),这时事务B要给user表上一个表级的排他锁就会被阻塞。意向锁通过这种方式实现了行锁和表锁共存且满足事务隔离性的要求。
意向共享锁(IS锁):事务在请求S锁前,要先获得IS锁
意向排他锁(IX锁):事务在请求X锁前,要先获得IX锁
在使用共享锁和独占锁之前,使用意图锁,意图锁是mysql自己加的,不需要我们自己手动加。
意向锁从表的层次上查看数据,以判断事物能否获得共享锁和独占锁,提高了系统的性能,不需从页或者行上检查。意向锁之间都是相互兼容的,但是与表级排它锁互斥。
5、 计划锁
Sch-M,Sch-S。对数据库结构改变时用Sch-M,对查询进行编译时用Sch-S。这两种锁不会阻塞任何事物锁,包括独占锁。
间隙锁:是基于InnoDB存储引擎,Repeatable Read隔离级别下(间隙锁是在可重复读隔离级别下才会生效),为解决在当前读的情况下幻读问题而提出。对主键索引和唯一索引不会有间隙锁,普通索引会有间隙锁。https://www.jianshu.com/p/0f3d45c645ac
next-key锁:其实包含了记录锁(行锁,行锁是的概念是在索引的基础上)和间隙锁,即锁定一个范围,并且锁定记录本身,InnoDB默认加锁方式是next-key 锁。在所以索引下查询,next-key锁会根据情况退化成记录锁或者间隙锁,比如记录存在,则是记录锁,记录不存在,则是间隙锁。
https://www.cnblogs.com/crazylqy/p/7821481.html
插入意向锁:是一种Gap锁,不是意向锁,在insert操作时产生。为了提高并发插入。
读是共享锁,写是排他锁,先读后更新的操作是更新锁,更新锁成功并且改变了数据时更新锁升级到排他锁。
死锁检测
直观方法是在两个事务相互等待时,当一个等待时间超过设置的某一阀值时,对其中一个事务进行回滚,另一个事务就能继续执行。这种方法简单有效,在innodb中,参数innodb_lock_wait_timeout用来设置超时时间。
仅用上述方法来检测死锁太过被动,innodb还提供了wait-for graph算法来主动进行死锁检测,每当加锁请求无法立即满足需要并进入等待时,wait-for graph算法都会被触发。wait-for graph算法用深度优先算法检测到事务之间形成的有向图是环路的,则认为存在死锁。
如何避免死锁
1 使用事务时,尽量缩短事务的逻辑处理过程,及早提交或回滚事务;
2 设置死锁超时参数为合理范围,如:3分钟-10分种;超过时间,自动放弃本次操作,避免进程悬挂;
3 所有的SP都要有错误处理(通过@error)
4 一般不要修改SQL SERVER事务的默认级别。不推荐强行加锁
5 优化程序,检查并避免死锁现象出现;
1)合理安排表访问顺序
2)在事务中尽量避免用户干预,尽量使一个事务处理的任务少些。
3)采用脏读技术。脏读由于不对被访问的表加锁,而避免了锁冲突。在客户机/服务器应用环境中,有些事务往往不允许读脏数据,但在特定的条件下,我们可以用脏读。
4)数据访问时域离散法。数据访问时域离散法是指在客户机/服务器结构中,采取各种控制手段控制对数据库或数据库中的对象访问时间段。主要通过以下方式实现: 合理安排后台事务的执行时间,采用工作流对后台事务进行统一管理。工作流在管理任务时,一方面限制同一类任务的线程数(往往限制为1个),防止资源过多占用; 另一方面合理安排不同任务执行时序、时间,尽量避免多个后台任务同时执行,另外,避免在前台交易高峰时间运行后台任务
5)数据存储空间离散法。数据存储空间离散法是指采取各种手段,将逻辑上在一个表中的数据分散到若干离散的空间上去,以便改善对表的访问性能。主要通过以下方法实现: 第一,将大表按行或列分解为若干小表; 第二,按不同的用户群分解。
6)使用尽可能低的隔离性级别。隔离性级别是指为保证数据库数据的完整性和一致性而使多用户事务隔离的程度,SQL92定义了4种隔离性级别:未提交读、提交读、可重复读和可串行。如果选择过高的隔离性级别,如可串行,虽然系统可以因实现更好隔离性而更大程度上保证数据的完整性和一致性,但各事务间冲突而死锁的机会大大增加,大大影响了系统性能。
7)使用Bound Connections。Bound connections 允许两个或多个事务连接共享事务和锁,而且任何一个事务连接要申请锁如同另外一个事务要申请锁一样,因此可以允许这些事务共享数据而不会有加锁的冲突。
8)考虑使用乐观锁定或使事务首先获得一个独占锁定。
死锁排查
mysql 设置 innodb_print_all_deadlocks=ON, 保存死锁日志
https://www.aneasystone.com/archives/2018/04/solving-dead-locks-four.html
外键约束之间的锁
(RR隔离级别,无间隙锁,外键没有on delete 或者on update)
子表 母表
insert 被外键关联的行加S锁
delete 被外键关联的行家S锁
update非关联字段 无锁
update关联字段 两个S锁,更新前的和更新后的行
select forupdate 无锁
母表的任何操作都不会给子表加锁。
(如果有级联删除或者级联更新等外键。母表外键字段变化后会给子表加X锁)
https://blog.csdn.net/zhongyangjian/article/details/51968675
http://hedengcheng.com/?p=771#_Toc374698322