锁是SQL Server数据库引擎用来同步多个用户同时对同一个数据块的访问的一种机制。
使用锁可以确保事务完整性和数据库一致性。锁可以防止用户读取正在由其他用户更改的数据,并可以防止多个用户同时更改相同的数据。
不使用锁可能会产生的问题
丢失或覆盖更新
当两个或者多个事务选择同一行,然后基于最初选定的值更新该行时会发生丢失更新问题。每个事务都不知道其他事务的存在。最后的更新将重写由其他事务所做的更新。这将导致数据丢失。
如果A和B同时对数student表中的id为00003的学生的年龄进行更改。A改成18,接着B改成22,A所做的修改没有被保存,B的修改保存 生效
未确认的相关性(脏读)
当第二个事务选择选择其他事务正在更新的行时,会发生未确认的相关性问题。第二个事务正在读取的数据还没有确认并且可能由更新此行的事务所更改。
比如A正在更改电子文档。在更改的过程中,B复制了该文档(该副本包含到目前位置所做的全部更改)并将其分发给预期的用户。此后,A认为目前所做的更改是错误的,于是删除了所做的编辑并保存了文档。分发给用户的文档包含不在存在的编辑内容(脏读),并且这些编辑内容应认为从未存在过。如果A确认最终更改前,任何人都不能读取更改的文档,则可以避免该问题。
不一致的分析
当第二个事务多次访问同一行而且每次读取不同的数据时,会发生不一致的分析问题。不一致的分析与未确认的相关性类似。因为其他事务也是正在更改第二个事务正在读取的数据。然而在不一致分析中,第二个事务读取的数据是由已进行更改的事务提交的。因而该行被非重复读取。
比如A两次读取同一个文档,但是两次读取之间,B重写了该文档。当A第二次读取该文档时,文档已经更改,原始读取不可重复。如果只有在完成编辑后,另外的人才可以读取文档,则可以避免这个问题。
幻象读
当对某行执行插入或者删除操作,而该行属于某个事务正在读取的范围时,会发生幻读现象。
感觉像出现了幻觉一样。
事务第一次读的行的范围显示出现其中一行已不复存在于第二次读或者后续读中的数据,因为该行已经被其他事务删除了。同样,由于其他事务的插入操作,事务的第二次或者后续读又多出了比第一次读的一些数据。
A正在像student表添加两个学生,学号应该自增到了101,和102,同时B在查看学好大于050的全部学生。第一次查出来的范围在050——100,第二次查就发现了范围在050——102了。如果在在B查看的同事任何人都不能像数据库添加或者删除数据,就能避免该问题
死锁及其防止
在两个或者多个任务中,如果每个任务锁定了其他任务视图锁定的资源。此时会造成这些问题永久阻塞,从而出现死锁。
在以下两种情况将出现死锁
- 当两个事务分别锁定了两个单独的对象,这时每个事务对象都要求在另一个事务锁定对象上面获得一个锁,因此每个事务都必须等待另一个事务释放占有的锁,这时就发生了死锁。这种死锁是最经典的死锁形式。例如:同一个时间内两个事务A和B,事务A有两个操作,锁定student表和请求访问sc表;事务B也有两个操作,锁定sc表和请其余访问student表。结果AB之间就会发生死锁。
- 在一个数据库中,有若干个长时间运行的事务,他们执行并行的操作当查询分析处理器是一种非常复杂的查询,如链接查询时,就可能由于不能控制处理的顺序而发生死锁。
在SQL Server中解决死锁的办法是:系统自动进行死锁检测,终止操作较少的事务以打断死锁,并向作为死锁牺牲品的事务发送错误的信息。
处理时死锁最好的方法就是防止死锁发生。
锁的模式
SQL Server数据库引擎使用了不同的锁模式锁定资源,这些锁模式确定了并发事务访问资源的方式。
共享锁
共享锁(S锁)允许并发事务在封闭式并发控制下读取(SELECT)资源。资源上存在S锁时,任何其他事务不能修改数据,读取操作已完成就立即释放S锁,除非将事务隔离级别设置为可重复读或者更高级,或者事务持续时间内用锁定提示保留S锁。
更新锁
更新锁(U锁)可以防止常见的死锁。在可重复读或可序列化事务中,此事务读取数据,即获取资源(页或行)的S锁;然后修改数据,此操作要求数据转换为排他锁(X锁)。如果两个事务获得了资源上的共享锁,然后试图同时更新数据,则一个事务尝试将锁转换为X锁。从S锁到X锁的转换必须等待一段时间,因为一个事务的X锁与其他事务的S锁不兼容,发生锁等待。第二个事务试图获取X锁以进行更新。由于两个事务都要转换为X锁,并且每个事务都等待另一个事务释放共享锁资源,因此发生死锁。
排他锁
排他锁(X锁)可以防止并发事务对资源进行访问。在使用X锁时,其他任何事务都无法修改数据。仅在使用NOLOCK提示或未提交读隔离级别时才会进行读取的操作,
意向锁
意向锁主要用来保护S锁和X锁放置在锁层次结构的底层资源上,可以在较低级别的锁前获取它们,因此会通知将意向锁防止在较低级别上。
意向锁有两个用途:
- 防止其他事务以使较低级别的锁无效的方式修改较高级别的资源
- 提高数据库在较高粒度级别检测锁冲突的效率
意向锁包括意向共享(IS),意向排他(IX),意向排他共享(SIX)
架构锁
数据库引擎在DDL操作的过程中使用架构修改(Sch-M)锁。保持该锁期间,Sch-M锁将阻止对表进行并发访问。这意味着Sch-M锁在释放前将阻止所有的外围操作。
数据库引擎在编译和执行查询时,使用架构稳定性(Sch-S)锁。Sch-S锁不会阻止某些事务锁。其中包括X锁。因此,在编译查询的过程中,其他事务将继续运行。但是,无法针对表执行获取Sch-M锁的并发DDL操作和并发DML操作。
大容量更新锁
数据库引擎在将数据大量复制到表中时,使用了大容量更新(BU)锁,并制定了TABLOCK提示或使用sp_tableoption设置了 table lock on bulk load表选项。大容量加载数据的进程访问该表。
键范围锁
在使用可序列化事务隔离级别时,对于T-SQL语句读取的记录集,键范围锁可以隐式保护该记录集中包含的行范围。键范围可防止幻读。通过保护行之间的范围,还防止对事务访问的记录集进行幻想插入或者删除。