SQL 死锁 with(nolock)详解

合集下载

sqlserver锁表语句

sqlserver锁表语句

sqlserver锁表语句SQL Server中可以使用锁表语句来对数据库中的表进行加锁,以保证数据的一致性和并发性。

下面列举了10个常用的SQL Server锁表语句:1. SELECT * FROM table_name WITH (NOLOCK)这是最常用的锁表语句之一,它会对表进行读取加锁,但不阻塞其他事务对该表的读取操作。

2. SELECT * FROM table_name WITH (UPDLOCK)这个语句会对表进行读取加锁,并且阻塞其他事务对该表的写入和删除操作。

3. SELECT * FROM table_name WITH (XLOCK)这个语句会对表进行写入加锁,并且阻塞其他事务对该表的读取、写入和删除操作。

4. SELECT * FROM table_name WITH (ROWLOCK)这个语句会对表的行进行加锁,而不是对整个表进行加锁,可以提高并发性能。

5. SELECT * FROM table_name WITH (TABLOCK)这个语句会对整个表进行加锁,阻塞其他事务对该表的任何操作。

6. SELECT * FROM table_name WITH (TABLOCKX)这个语句会对整个表进行排他性加锁,阻塞其他事务对该表的任何操作。

7. BEGIN TRANSACTION这个语句用于开始一个事务,在事务内的操作会自动加锁。

8. COMMIT TRANSACTION这个语句用于提交一个事务,释放事务中的锁。

9. ROLLBACK TRANSACTION这个语句用于回滚一个事务,取消事务中的操作,并释放锁。

10. SET TRANSACTION ISOLATION LEVEL这个语句用于设置事务的隔离级别,以控制事务对数据库的锁定行为。

需要注意的是,在使用锁表语句时,应根据实际业务需求和数据库性能进行选择和调整。

过多的加锁可能会导致死锁和性能问题,而过少的加锁可能会导致数据不一致。

sqlserver中避免死锁的方法

sqlserver中避免死锁的方法

sqlserver中避免死锁的方法一、死锁的四个必要条件1、互斥条件(Mutualexclusion):资源不能被共享,只能由一个进程使用。

2、请求与保持条件(Holdandwait):已经得到资源的进程可以再次申请新的资源。

3、非剥夺条件(Nopre-emption):已经分配的资源不能从相应的进程中被强制地剥夺。

4、循环等待条件(Circularwait):系统中若干进程组成环路,该环路中每个进程都在等待相邻进程正占用的资源。

二、避免死锁1、按同一顺序访问对象如果所有并发事务按同一顺序访问对象,则发生死锁的可能*会降低。

例如,如果两个并发事务获得Supplier表上的锁,然后获得Part 表上的锁,则在其中一个事务完成之前,另一个事务被阻塞在Supplier表上。

第一个事务提交或回滚后,第二个事务继续进行。

不发生死锁。

将存储过程用于所有的数据修改可以标准化访问对象的顺序。

2、避免事务中的用户交互避免编写包含用户交互的事务,因为运行没有用户交互的批处理的速度要远远快于用户手动响应查询的速度,例如答复应用程序请求参数的提示。

例如,如果事务正在等待用户输入,而用户去吃午餐了或者甚至回家过周末了,则用户将此事务挂起使之不能完成。

这样将降低系统的吞吐量,因为事务持有的任何锁只有在事务提交或回滚时才会释放。

即使不出现死锁的情况,访问同一资源的其它事务也会被阻塞,等待该事务完成。

3、保持事务简短并在一个批处理中在同一数据库中并发执行多个需要长时间运行的事务时通常发生死锁。

事务运行时间越长,其持有排它锁或更新锁的时间也就越长,从而堵塞了其它活动并可能导致死锁。

保持事务在一个批处理中,可以最小化事务的网络通信往返量,减少完成事务可能的延迟并释放锁。

4、使用低隔离级别确定事务是否能在更低的隔离级别上运行。

执行提交读允许事务读取另一个事务已读取(未修改)的数据,而不必等待第一个事务完成。

使用较低的隔离级别(例如提交读)而不使用较高的隔离级别(例如可串行读)可以缩短持有共享锁的时间,从而降低了锁定争夺。

SQLServer死锁产生原因及解决方法

SQLServer死锁产生原因及解决方法

SQLServer死锁产⽣原因及解决⽅法⼀、什么是死锁死锁是指两个或两个以上的进程在执⾏过程中,因争夺资源⽽造成的⼀种互相等待的现象,若⽆外⼒作⽤,它们都将⽆法推进下去.此时称系统处于死锁状态或系统产⽣了死锁,这些永远在互相等的进程称为死锁进程.⼆、死锁产⽣的四个必要条件互斥条件:指进程对所分配到的资源进⾏排它性使⽤,即在⼀段时间内某资源只由⼀个进程占⽤。

如果此时还有其它进程请求资源,则请求者只能等待,直⾄占有资源的进程⽤毕释放请求和保持条件:指进程已经保持⾄少⼀个资源,但⼜提出了新的资源请求,⽽该资源已被其它进程占有,此时请求进程阻塞,但⼜对⾃⼰已获得的其它资源保持不放不剥夺条件:指进程已获得的资源,在未使⽤完之前,不能被剥夺,只能在使⽤完时由⾃⼰释放环路等待条件:指在发⽣死锁时,必然存在⼀个进程——资源的环形链,即进程集合{P0,P1,P2,···,Pn}中的P0正在等待⼀个P1占⽤的资源;P1正在等待P2占⽤的资源,……,Pn正在等待已被P0占⽤的资源这四个条件是死锁的必要条件,只要系统发⽣死锁,这些条件必然成⽴,⽽只要上述条件之⼀不满⾜,就不会发⽣死锁。

三、如何处理死锁1) 锁模式1. 共享锁(S)由读操作创建的锁,防⽌在读取数据的过程中,其它事务对数据进⾏更新;其它事务可以并发读取数据。

共享锁可以加在表、页、索引键或者数据⾏上。

在SQL SERVER默认隔离级别下数据读取完毕后就会释放共享锁,但可以通过锁提⽰或设置更⾼的事务隔离级别改变共享锁的释放时间。

2.独占锁(X)对资源独占的锁,⼀个进程独占地锁定了请求的数据源,那么别的进程⽆法在此数据源上获得任何类型的锁。

独占锁⼀致持有到事务结束。

3.更新锁(U)更新锁实际上并不是⼀种独⽴的锁,⽽是共享锁与独占锁的混合。

当SQL SERVER执⾏数据修改操作却⾸先需要搜索表以找到需要修改的资源时,会获得更新锁。

更新锁与共享锁兼容,但只有⼀个进程可以获取当前数据源上的更新锁,其它进程⽆法获取该资源的更新锁或独占锁,更新锁的作⽤就好像⼀个序列化阀门(serialization gate),将后续申请独占锁的请求压⼊队列中。

SQL中with(nolock)详解

SQL中with(nolock)详解

SQL中with(nolock)详解大家在写查询时,为了性能,往往会在表后面加一个nolock,或者是with(nolock),其目的就是查询是不锁定表,从而达到提高查询速度的目的。

什么是并发访问:同一时间有多个用户访问同一资源,并发用户中如果有用户对资源做了修改,此时就会对其它用户产生某些不利的影响,例如: 1:脏读,一个用户对一个资源做了修改,此时另外一个用户正好读取了这条被修改的记录,然后,第一个用户放弃修改,数据回到修改之前,这两个不同的结果就是脏读。

2:不可重复读,一个用户的一个操作是一个事务,这个事务分两次读取同一条记录,如果第一次读取后,有另外用户修改了这个数据,然后第二次读取的数据正好是其它用户修改的数据,这样造成两次读取的记录不同,如果事务中锁定这条记录就可以避免。

3:幻读,指用户读取一批记录的情况,用户两次查询同一条件的一批记录,第一次查询后,有其它用户对这批数据做了修改,方法可能是修改,删除,新增,第二次查询时,会发现第一次查询的记录条目有的不在第二次查询结果中,或者是第二次查询的条目不在第一次查询的内容中。

为什么会在查询的表后面加nolock标识?为了避免并发访问产生的不利影响,SQL Server有两种并发访问的控制机制:锁、行版本控制,表后面加nolock 是解决并发访问的方案之一。

1> 锁,每个事务对所依赖的资源会请求不同类型的锁,它可以阻止其他事务以某种可能会导致事务请求锁出错的方式修改资源。

当事务不再依赖锁定的资源时,锁将被释放。

锁的类型:1:表类型:锁定整个表;2:行类型:锁定某个行;3:文件类型:锁定某个数据库文件;4:数据库类型:锁定整个数据库;5:页类型:锁定8K为单位的数据库页。

锁的分类还有一种分法,就是按用户和数据库对象来分:1). 从数据库系统的角度来看:分为独占锁(即排它锁),共享锁和更新锁1:共享 (S) :用于不更改或不更新数据的操作(只读操作),一般常见的例如select语句。

sql server中如何避免死锁

sql server中如何避免死锁

一、死锁的四个必要条件1、互斥条件(Mutual exclusion):资源不能被共享,只能由一个进程使用。

2、请求与保持条件(Hold and wait):已经得到资源的进程可以再次申请新的资源。

3、非剥夺条件(No pre-emption):已经分配的资源不能从相应的进程中被强制地剥夺。

4、循环等待条件(Circular wait):系统中若干进程组成环路,该环路中每个进程都在等待相邻进程正占用的资源。

二、避免死锁1、按同一顺序访问对象如果所有并发事务按同一顺序访问对象,则发生死锁的可能性会降低。

例如,如果两个并发事务获得Supplier 表上的锁,然后获得Part 表上的锁,则在其中一个事务完成之前,另一个事务被阻塞在Supplier 表上。

第一个事务提交或回滚后,第二个事务继续进行。

不发生死锁。

将存储过程用于所有的数据修改可以标准化访问对象的顺序。

2、避免事务中的用户交互避免编写包含用户交互的事务,因为运行没有用户交互的批处理的速度要远远快于用户手动响应查询的速度,例如答复应用程序请求参数的提示。

例如,如果事务正在等待用户输入,而用户去吃午餐了或者甚至回家过周末了,则用户将此事务挂起使之不能完成。

这样将降低系统的吞吐量,因为事务持有的任何锁只有在事务提交或回滚时才会释放。

即使不出现死锁的情况,访问同一资源的其它事务也会被阻塞,等待该事务完成。

3、保持事务简短并在一个批处理中在同一数据库中并发执行多个需要长时间运行的事务时通常发生死锁。

事务运行时间越长,其持有排它锁或更新锁的时间也就越长,从而堵塞了其它活动并可能导致死锁。

保持事务在一个批处理中,可以最小化事务的网络通信往返量,减少完成事务可能的延迟并释放锁。

4、使用低隔离级别确定事务是否能在更低的隔离级别上运行。

执行提交读允许事务读取另一个事务已读取(未修改)的数据,而不必等待第一个事务完成。

使用较低的隔离级别(例如提交读)而不使用较高的隔离级别(例如可串行读)可以缩短持有共享锁的时间,从而降低了锁定争夺。

sqlserver锁表

sqlserver锁表

sqlserver锁表项⽬运⾏过程提⽰了死锁,⼀个select查询和⼀个update的更新居然出现了死锁,本⾝select会有共享锁,update会有排它锁,但是我的两个语句⽬前应该不符合那种特殊情况(特殊情况会导致select和update死锁)于是做了实:1)编写⼀个⼀直运⾏的selectwhile 1=1beginselect balance from bo_account_wallet where accountsubid=10046end2)查询当前是否有锁表的情况selectrequest_session_id spid,OBJECT_NAME(resource_associated_entity_id) tableNamefromsys.dm_tran_lockswhereresource_type='OBJECT'此时并⽆锁表,难道有错??于是⽤update做了确定:同样的操作:1)编写⼀个更新语句while 1=1beginupdate bo_account_wallet set islock=1 where accountsubid=10046end2)查询锁表情况selectrequest_session_id spid,OBJECT_NAME(resource_associated_entity_id) tableNamefromsys.dm_tran_lockswhereresource_type='OBJECT'此时会有锁表的spid3)查询当前的锁类型EXEC sp_who activeexec sp_lock说明这种实验是可以验证的;后来找到原因了,我的代码中查询是通过存储过程的,所以将实验修改为:while 1=1beginexec EncryptAndDecrypt 'cetIBS20201012Pa$$word','select balance from bo_account_wallet with(nolock) where accountsubid=10046'end此时看到锁表信息了,这说明存储过程会有加锁的情况。

sqlserver锁(lock)的基础及应用

sqlserver锁(lock)的基础及应用

sqlserver锁(lock)的基础及应⽤⼀关于锁的基础知识(⼀). 为什么要引⼊锁当多个⽤户同时对的并发操作时会带来以下数据不⼀致的问题:◆丢失更新A,B两个⽤户读同⼀数据并进⾏修改,其中⼀个⽤户的修改结果破坏了另⼀个修改的结果,⽐如订票系统◆脏读A⽤户修改了数据,随后B⽤户⼜读出该数据,但A⽤户因为某些原因取消了对数据的修改,数据恢复原值,此时B得到的数据就与数据库内的数据产⽣了不⼀致◆不可重复读A⽤户读取数据,随后B⽤户读出该数据并修改,此时A⽤户再读取数据时发现前后两次的值不⼀致并发控制的主要⽅法是封锁,锁就是在⼀段时间内禁⽌⽤户做某些操作以避免产⽣数据不⼀致(⼆) 锁的分类◆锁的类别有两种分法:1. 从数据库系统的⾓度来看:分为独占锁(即排它锁),共享锁和更新锁MS-SQL Server 使⽤以下资源锁模式。

锁模式描述共享 (S) ⽤于不更改或不更新数据的操作(只读操作),如 SELECT 语句。

更新 (U) ⽤于可更新的资源中。

防⽌当多个会话在读取、锁定以及随后可能进⾏的资源更新时发⽣常见形式的死锁。

排它 (X) ⽤于数据修改操作,例如 INSERT、UPDATE 或 DELETE。

确保不会同时同⼀资源进⾏多重更新。

意向锁⽤于建⽴锁的层次结构。

意向锁的类型为:意向共享 (IS)、意向排它 (IX) 以及与意向排它共享 (SIX)。

锁在执⾏依赖于表架构的操作时使⽤。

架构锁的类型为:架构修改 (Sch-M) 和架构稳定性 (Sch-S)。

⼤容量更新 (BU) 向表中⼤容量复制数据并指定了 TABLOCK 提⽰时使⽤。

◆共享锁共享 (S) 锁允许并发事务读取 (SELECT) ⼀个资源。

资源上存在共享 (S) 锁时,任何其它事务都不能修改数据。

⼀旦已经读取数据,便⽴即释放资源上的共享 (S)锁,除⾮将事务隔离级别设置为可重复读或更⾼级别,或者在事务⽣存周期内⽤锁定提⽰保留共享 (S) 锁。

SQLServer中WITH(NOLOCK)浅析

SQLServer中WITH(NOLOCK)浅析

SQLServer中WITH(NOLOCK)浅析概念介绍开发⼈员喜欢在SQL脚本中使⽤WITH(NOLOCK), WITH(NOLOCK)其实是表提⽰(table_hint)中的⼀种。

它等同于READUNCOMMITTED 。

具体的功能作⽤如下所⽰(摘⾃MSDN):1:指定允许脏读。

不发布共享锁来阻⽌其他事务修改当前事务读取的数据,其他事务设置的排他锁不会阻碍当前事务读取锁定数据。

允许脏读可能产⽣较多的并发操作,但其代价是读取以后会被其他事务回滚的数据修改。

这可能会使您的事务出错,向⽤户显⽰从未提交过的数据,或者导致⽤户两次看到记录(或根本看不到记录)。

有关脏读、不可重复读和幻读的详细信息,请参阅。

2: READUNCOMMITTED 和 NOLOCK 提⽰仅适⽤于数据锁。

所有查询(包括那些带有 READUNCOMMITTED 和 NOLOCK 提⽰的查询)都会在编译和执⾏过程中获取 Sch-S(架构稳定性)锁。

因此,当并发事务持有表的 Sch-M(架构修改)锁时,将阻塞查询。

例如,数据定义语⾔ (DDL) 操作在修改表的架构信息之前获取 Sch-M 锁。

所有并发查询(包括那些使⽤ READUNCOMMITTED 或 NOLOCK 提⽰运⾏的查询)都会在尝试获取 Sch-S 锁时被阻塞。

相反,持有 Sch-S 锁的查询将阻塞尝试获取 Sch-M 锁的并发事务。

有关锁⾏为的详细信息,请参阅。

3: 不能为通过插⼊、更新或删除操作修改过的表指定 READUNCOMMITTED 和 NOLOCK。

SQL Server 查询优化器忽略 FROM ⼦句中应⽤于 UPDATE 或 DELETE 语句的⽬标表的 READUNCOMMITTED 和 NOLOCK 提⽰。

功能与缺陷使⽤WIHT(NOLOCK)有利也有弊,所以在决定使⽤之前,你⼀定需要了解清楚WITH(NOLOCK)的功能和缺陷,看其是否适合你的业务需求,不要觉得它能提升性能,稀⾥糊涂的就使⽤它。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

大家在写查询时,为了性能,往往会在表后面加一个nolock,或者是with(nolock),其目的就是查询是不锁定表,从而达到提高查询速度的目的。

什么是并发访问:同一时间有多个用户访问同一资源,并发用户中如果有用户对资源做了修改,此时就会对其它用户产生某些不利的影响,例如:
1:脏读,一个用户对一个资源做了修改,此时另外一个用户正好读取了这条被修改的记录,然后,第一个用户放弃修改,数据回到修改之前,这两个不同的结果就是脏读。

2:不可重复读,一个用户的一个操作是一个事务,这个事务分两次读取同一条记录,如果第一次读取后,有另外用户修改了这个数据,然后第二次读取的数据正好是其它用户修改的数据,这样造成两次读取的记录不同,如果事务中锁定这条记录就可以避免。

3:幻读,指用户读取一批记录的情况,用户两次查询同一条件的一批记录,第一次查询后,有其它用户对这批数据做了修改,方法可能是修改,删除,新增,第二次查询时,会发现第一次查询的记录条目有的不在第二次查询结果中,或者是第二次查询的条目不在第一次查询的内容中。

为什么会在查询的表后面加nolock标识?为了避免并发访问产生的不利影响,SQL Server有两种并发访问的控制机制:锁、行版本控制,表后面加nolock是解决并发访问的方案之一。

1> 锁,每个事务对所依赖的资源会请求不同类型的锁,它可以阻止其他事务以某种可能会导致事务请求锁出错的方式修改资源。

当事务不再依赖锁定的资源时,锁将被释放。

锁的类型:1:表类型:锁定整个表;2:行类型:锁定某个行;3:文件类型:锁定某个数据库文件;4:数据库类型:锁定整个数据库;5:页类型:锁定8K为单位的数据库页。

锁的分类还有一种分法,就是按用户和数据库对象来分:
1). 从数据库系统的角度来看:分为独占锁(即排它锁),共享锁和更新锁
1:共享(S) :用于不更改或不更新数据的操作(只读操作),一般常见的例如select语句。

2:更新(U) :用于可更新的资源中。

防止当多个会话在读取、锁定以及随后可能进行的资源更新时发生常见形式的死锁。

3:排它(X) :用于数据修改操作,例如INSERT、UPDATE 或DELETE。

确保不会同时同一资源进行多重更新。

2). 从程序员的角度看:分为乐观锁和悲观锁。

1:乐观锁:完全依靠数据库来管理锁的工作。

2:悲观锁:程序员自己管理数据或对象上的锁处理。

一般程序员一看到什么锁之类,觉的特别复杂,对专业的DBA当然是入门级知识了。

可喜的是程序员不用去设置,控制这些锁,SQLServer通过设置事务的隔离级别自动管理锁的设置和控制。

锁管理器通过查询分析器分析待执行的sql语句,来判断语句将会访问哪些资源,进行什么操作,然后结合设定的隔离级别自动分配管理需要用到的锁。

2>:行版本控制:当启用了基于行版本控制的隔离级别时,数据库引擎将维护修改的每一行的版本。

应用程序可以指定事务使用行版本查看事务或查询开始时存在的数据,而不是使用锁保护所有读取。

通过使用行版本控制,读取操作阻止其他事务的可能性将大大降低。

也就是相当于针对所有的表在查询时都会加上nolock,同样会产生脏读的现象,但差别在于在一个统一管理的地方。

说到了基于行版本控制的隔离级别,这里有必要说下隔离级别的概念。

隔离级别的用处:控制锁的应用,即什么场景应用什么样的锁机制。

最终目的:解决并发处理带来的种种问题。

隔离级别的分类:
1:未提交读,隔离事务的最低级别,只能保证不读取物理上损坏的数据;
2:已提交读,数据库引擎的默认级;
3:可重复读;
4:可序列化;隔离事务的最高级别,事务之间完全隔离。

小结:NOLOCK 语句执行时不发出共享锁,允许脏读,等于READ UNCOMMITTED事务隔离级别。

nolock确实在查询时能提高速度,但它并不是没有缺点的,起码它会引起脏读。

nolock的使用场景(个人观点):
1:数据量特别大的表,牺牲数据安全性来提升性能是可以考虑的;
2:允许出现脏读现象的业务逻辑,反之一些数据完整性要求比较严格的场景就不合适了,像金融方面等。

3:数据不经常修改的表,这样会省于锁定表的时间来大大加快查询速度。

综上所述,如果在项目中的每个查询的表后面都加nolock,这种做法并不科学,起码特别费时间,不如行版本控制来的直接有效。

而且会存在不可预期的技术问题。

应该有选择性的挑选最适合的表来放弃共享锁的使用。

最后说下nolock和with(nolock)的几个小区别:
1:SQL05中的同义词,只支持with(nolock);
2:with(nolock)的写法非常容易再指定索引。

跨服务器查询语句时不能用with (nolock) 只能用nolock
同一个服务器查询时则with (nolock)和nolock都可以用
比如
SQL code
select * from [IP].a.dbo.table1 with (nolock) 这样会提示用错误select * from a.dbo.table1 with
(nolock) 这样就可以。

相关文档
最新文档