SQL Server-聚焦NOLOCK、UPDLOCK、HOLDLOCK、READPAST你弄懂多少?(三十四)

前言

时间流逝比较快,博主也在快马加鞭学习SQL Server,下班回来再晚也不忘记更新下博客,时间挤挤总会有的,现在的努力求的是未来所谓的安稳,每学一门为的是深度而不是广度,求的是知识自成体系而不是零散,废话不多说本节我们来讲讲SQL Server基础系列最后几节内容,这话博主说了n次,呵呵。

NOLOCK和READPAST

NOLOCK

随便翻翻博客园对于各种锁的介绍真的是一个字【多】,仅仅介绍其概念,再要么就是转载其概念,不知道那些转载概念的园友是否已经弄懂了,稍微发下感慨。NOLOCK在概念上类似于READ UNCOMMITTED隔离级别,并且只针对于SELECT查询语句,它不会获取表的共享锁,换句话说不会阻止排它锁来更新数据行。当我们对表进行NOLOCK有什么好处呢?它能够提高并发性能,因为此时SQL Server数据库引擎不必去维护共享锁,由于不会对正在读取的表获取共享锁,所以可能导致未提交的事务也会被读取,所以此时缺点显而易见将导致脏读,至于脏读是何含义则无需我再多讲。我们重点的明白什么情况下应该用NOLOCK。我们看下实际例子来理解NOLOCK,建立测试表并插入300条测试数据:

IF OBJECT_ID('Example')>0      

DROP TABLE Example;

GO

CREATE TABLE [dbo].[Example]

(
      [SaleID] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
      [Product] [char](150) NULL,
            [SaleDate] [datetime] NULL,
            [SalePrice] [money] NULL
)

GO

DECLARE @i SMALLINT

SET @i = 1

WHILE (@i <=100)

BEGIN
      INSERT INTO Example
      (Product, SaleDate, SalePrice)
      VALUES
      ('Computer', DATEADD(mm, @i, '3/11/1919'), DATEPART(ms, GETDATE()) + (@i + 57))      

      INSERT INTO Example
      (Product, SaleDate, SalePrice)
      VALUES
      ('BigScreen', DATEADD(mm, @i, '3/11/1927'), DATEPART(ms, GETDATE()) + (@i + 13))                  

      INSERT INTO Example
      (Product, SaleDate, SalePrice)
      VALUES
      ('PoolTable', DATEADD(mm, @i, '3/11/1908'), DATEPART(ms, GETDATE()) + (@i + 29))                  

      SET @i = @i + 1

END

GO

此时我们再来插入一条测试数据:

BEGIN TRANSACTION
      INSERT INTO Example
      (Product, SaleDate, SalePrice)
      VALUES
      ('PoolTable', GETDATE(), 500) 

此时我们保持该事务窗口打开,所以此时在表中仍然会记录着对其所发出的锁,接下来我们在另外一个窗口查询表中数据总行数并使用NOLOCK提示。

SELECT COUNT(*) FROM Example WITH(NOLOCK)

此时显示数据总函数为301,因为上述插入语句的事务进入到了表中只是并未提交而已,此时我们不想插入那条数据进行撤销即回滚

BEGIN TRANSACTION
      INSERT INTO Example
      (Product, SaleDate, SalePrice)
      VALUES
      ('PoolTable', GETDATE(), 500)
ROLLBACK TRANSACTION

此时我们回滚了之前插入的数据,我们再来利用NOLOCK提示来查询数据总函数。

此时返回的为实际总数据行,而我么第一次查询的数据并未提交这就是典型的-脏读。

READPAST

READPAST表提示相信很多童鞋用的比较少,但是实际上其作用非常大,当在表中用READPAST指定提示时此时SQL Server数据库引擎在返回结果集时将不会返回锁定的行或者数据页。它除了和NOLOCK一样不会导致查询阻塞外,因为不会返回锁定的行记录所以其优点好包括不存在脏读。但是其缺点则是因为不包含锁定的行记录但是很难保证结果集或者修改语句是否包含我们所必须需要返回的行。有可能在我们的业务逻辑中,需要返回我们必须需要的行。它的使用方式和NOLOCK一样,下面我们来看下实际例子,更新测试表中的SalePrice列,如下:

BEGIN TRANSACTION
      UPDATE TOP(1) Example
      SET SalePrice = SalePrice + 1

由于我们并未提交或者回滚事务所以此时更新的数据行已经被影响,下面我们利用READPAST提示来查询表中总数据行。

SELECT COUNT(*)

FROM Example WITH(READPAST)

在我们的测试表中数据行为300条,同时我们进行了上述更新,当我们利用READPAST提示进行查询总数据行时,因为更新而未提交或者回滚导致此时有一行记录被排它锁锁住,而READPAST的作用则是跳过锁住的行,所以此时很明显只返回299条数据,如下:

通过上述图显示由于更新数据行被锁定,所以此时利用READPAST来查询总数据行时导致更新数据行将被忽略。

UPDLOCK和HOLDLOCK

UPDLOCK

怎么会出现一个更新锁的呢,原来我们对于查询和更新死锁说到了排它锁,这个排它锁和更新锁不是一样的么,此言差矣,容我娓娓道来,这个UPDLOCK只是针对于表中的某一行记录来锁定从而阻止其他操作对该行的数据更新,说到这里想必我们已经明了,UPDLOCK是行级别,而排它锁则是表级别,二者不可同日而语。也就说当我们对某一行添加UPDLOCK提示时并不会阻塞其他查询操作,下面我们来看看,我们打开一个窗口来更新测试表中筛选条件为SaleID等于1的记录并用UPDLOCK锁住。

 BEGIN TRAN
 select * from Example WITH (UPDLOCK) where SaleID = 1

此时我们再来开一个窗口进行查询,如下:

select * from Example

此时我们将看到能够查询出所有数据,如下:

HOLDLOCK

这个又是什么玩意了,根据词达意翻译为厚住锁【哈哈】,这个翻译虽然有点勉强,但是非常明确的表达了其意思,有点强制性的意味,当我们使用HOLDLOCK提示时,此时查询将锁定表且被强制序列化,直到事务完成,才会被释放,其类似于SERIALIZABLE最高隔离级别。我们结合上述例子来看下,当我们对表进行HOLDLOCK后再进行查询

 BEGIN TRAN
 select * from Example WITH (UPDLOCK,HOLDLOCK) where SaleID = 1

此时我们再来运行查询

 select * from Example

什么情况还是能查询出数据,不知道看到本文的你是否心生疑窦,我们并未提交事务并用UPDLOCK和HOLDLOCK提示此时再查询时应该会出现阻塞,因为此时已有排它锁的存在。我们先搁置疑问,在我们创建测试表时毫无疑问会对主键创建聚集索引,此时我们删除聚集索引试试。

此时我们重新运行上述语句,此时将导致查询阻塞,如下:

我们简短的解释一下,如果我们对表建立了聚集索引或非聚集索引此时排它锁将消失代替的则是RangeS-U锁,所以当我们未添加聚集索引排它锁则存在导致查询阻塞,有关RangeS-S,RangeS-U,RangeX-X,RangeI-N我们将深入研究。所以上述由于导致了查询阻塞,我们结合本节所学内容,我们利用NOLOCK来查询数据。

 select * from Example WITH(NOLOCK)

此时毫无疑问将能够查询出数据,如下:

当然除非我们意识到NOLOCK导致脏读的问题,否则谨慎用。

实战拓展

关于NOLOCK和UPDLOCK以及HOLDLOCK则没有什么可讲的,我们来讲讲UPDLOCK和READPAST,通过UPDLOCK和READPAST的结合我们能够解决许多问题,比如我当前项目中对于更新预约人数,则用到了UPDLOCK和READPAST,因为考虑到并发如果固定预约人数为100,那么当出现并发时将有可能导致预约超出的情况,利用UPDLOCK则可以解决其他进程过来时对其进行修改的情况,同时结合READPAST解决脏读,同时不会阻塞,当有请求过来时我们直接利用表变量对预约人数进行更新,若更新失败我们再进行回滚,算是一个解决方案。同时利用UPDLOCK和READPAST还可以解决其他问题,比如,当有多个并发时我们要根据筛选条件获取第一值,也就是说第二个请求过来时获取到的值是下一个,那么这样的问题该如何处理呢,若我们只是简单进行处理,那么第二个请求同时过来时可能也会读取到之前读取的那个值,基于此场景,我们可以利用UPDLOCK和READPAST来解决。我们看如下代码就可以理解。

DECLARE @Next INTEGER
BEGIN TRANSACTION

-- 找到下一个满足条件的值
SELECT TOP 1 @Next = Id
FROM Test WITH (UPDLOCK, READPAST)
WHERE Flag = 0
ORDER BY Id ASC

--若找到利用标识更新,防止下一次被读取到
IF (@Next IS NOT NULL)
    BEGIN
        UPDATE Test
        SET Flag = 1
        WHERE Id = @Next
    END

COMMIT TRANSACTION

-- 返回我们查询到的值
IF (@Next IS NOT NULL)
    SELECT * FROM Test WHERE Id = @Next

当然上述可以避免阻塞,我们也可以在阻塞的情况下来处理利用ROWLOCK和HOLDLOCK来解决

BEGIN TRAN

SELECT
FROM Test
WITH (HOLDLOCK, ROWLOCK)
WHERE Id = 1

--TODO

COMMIT TRAN

总结 

本节我们讲述了博主比较疑惑的几种锁例如READPAST,之前未接触过,项目中在老大的指导下才知道,本来打算今天结束SQL Server基础系列,谁知中途学习时遇到了其他问题,比如还有其他四种锁类型,我还得再研究研究,真的是SQL Server基础系列最后一篇,真的不骗你,同时.NET Core也会不定时更新,欢迎大家继续关注博客和公众号。

时间: 2024-09-20 15:35:42

SQL Server-聚焦NOLOCK、UPDLOCK、HOLDLOCK、READPAST你弄懂多少?(三十四)的相关文章

浅析SQL Server 聚焦索引对非聚集索引的影响

前言 在学习SQL 2012基础教程过程中会时不时穿插其他内容来进行讲解,相信看过SQL Server 2012 T-SQL基础教程的童鞋知道前面写的所有内容并非都是摘抄书上内容,如若是这样那将没有任何意义,学习的过程必须同时也是一个思考的过程,无论是独立思考也好还是查资料也罢都是思考而非走马观花,要不然过一段时间又会健忘.简短的内容,深入的理解. 话题 非聚集索引定义:非聚集索引也是一个B树结构,与聚集索引不同的是,B树的叶子节点存的是指向堆或聚集索引的指针.你真的理解了吗??你能举出例子吗?

浅析SQL Server的聚焦使用索引和查询执行计划_MsSql

前言 上一篇<浅析SQL Server 聚焦索引对非聚集索引的影响>我们讲了聚集索引对非聚集索引的影响,对数据库一直在强调的性能优化,所以这一节我们统筹讲讲利用索引来看看查询执行计划是怎样的,简短的内容,深入的理解. 透过索引来看查询执行计划 我们首先来看看第一个例子 1.默认使用索引 USE TSQL2012 GO SELECT orderid FROM Sales.Orders SELECT * FROM Sales.Orders 上述我们看到第2个查询的所需要的开销是第1个查询开销的3倍

浅析SQL Server的聚焦使用索引和查询执行计划

前言 上一篇<浅析SQL Server 聚焦索引对非聚集索引的影响>我们讲了聚集索引对非聚集索引的影响,对数据库一直在强调的性能优化,所以这一节我们统筹讲讲利用索引来看看查询执行计划是怎样的,简短的内容,深入的理解. 透过索引来看查询执行计划 我们首先来看看第一个例子 1.默认使用索引 USE TSQL2012 GO SELECT orderid FROM Sales.Orders SELECT * FROM Sales.Orders 上述我们看到第2个查询的所需要的开销是第1个查询开销的3倍

SQL Server数据库的锁类型

SQL Server锁: 1.HOLDLOCK: 在该表上保持共享锁,直到整个事务结束,而不是在语句执行完立即释放所添加的锁. 2.NOLOCK:不添加共享锁和排它锁,当这个选项生效后,可能读到未提交读的数据或"脏数据",这个选项仅仅应用于select语句. 3.PAGLOCK:指定添加页锁(否则通常可能添加表锁). 4.READCOMMITTED用与运行在提交读隔离级别的事务相同的锁语义执行扫描.默认情况下,SQL Server 2000 在此隔离级别上操作.. 5.READPAST

SQL Server数据库升级常见的五大错误

SQL Server数据库升级需要DBA进行大量的规划与测试.大多数的时间里,升 级过程也许不会出现任何问题,但是一些潜在的威胁绝不能忽视.在本文中,SQL Server专家Roman Rehak将为您介绍数据库升级或者迁移过程中,DBA应该注意哪 些问题. 升级测试不足.在SQL Server数据库升级出现问题的情况下,其 中最常见的原因就是测试不足.DBA不仅需要对每一个连接数据库的应用进行测试 ,还需要测试任何一个执行数据库代码的程序,比如SSIS包.数据库工具.辅助 存储过程以及复制等.

sql server 2000 的 jdbc 连接

server 这几天开始为红凤办的网站做筹备工作,首当其冲的就是将SQL Server 的jdbc连接调试好.首先下载了很多的源代码文件.比如网上的新闻发布系统,社区管理系统等等,各种各样的使用SQL Server的jsp源代码.开始了我的漫长而又让人沮丧的数据库连接工作.        首先先确定一下我使用的工具是eclipse 3.2 + tomcat 6.0 + jdk1.6,操作系统是window xp sp2.        步骤一:安装SQL Server 2000(我开始安装了SQ

SQL SERVER的数据类型

server|数据|数据类型 1.SQL SERVER的数据类型 数据类弄是数据的一种属性,表示数据所表示信息的类型.任何一种计算机语言都定义了自己的数据类型.当然,不同的程序语言都具有不同的特点,所定义的数据类型的各类和名称都或多或少有些不同.SQLServer 提供了 25 种数据类型: ·Binary [(n)] ·Varbinary [(n)] ·Char [(n)] ·Varchar[(n)] ·Nchar[(n)] ·Nvarchar[(n)] ·Datetime ·Smalldat

简述VC_ADO连接SQL SERVER时连接字符串的模式

一.连接SQL SERVER的第一种连接字串: 是针对数据库身份验证模式为"SQL SERVER 和 windows"而言, 连接字串为: CString strConn; strConn = "Provider = SQLOLEDB.1;\ Persist Security Info = true;\ User ID = sa;\ Password=123456;\ Initial Catalog = tempdb;\ Data Source = 127.0.0.1&quo

如何用PowerDesigner设计SQL Server数据库

  工具: Sybase PowerDesigner 12.5 Microsoft SQL Server 2005 第一步:概要设计 打开PowerDesigner软件,设计"概念数据模型"(Conceptual Data Model): 图1 设计表结构: 图2 在设计属性(字段)的时候,三个字母(M.P.D)分别表示: M:是否为空;(√表示不允许为空) P:是否为主键; D:是否在该软件的视图中显示; 第二步:详细设计 将"概念数据模型"设计的表转换为&quo