Sql server 2008 SQL Server 2008:选择以进行更新

Sql server 2008 SQL Server 2008:选择以进行更新,sql-server-2008,locking,Sql Server 2008,Locking,我在这里看到了一个关于这个问题的问题,但它是旧的,所以我将再次询问,以防现在存在一个解决方案 我的问题是这个。我有一个数据库表,我想从中选择,但我想锁定我选择的行。这样做的原因是,我可能有另一个进程正在运行,该进程也希望选择相同的行,我希望防止这种情况发生 假设我有两个进程在做同一件事。执行选择并开始对数据进行处理。几秒钟后,下一个进程出现并执行select,但由于行未被锁定,因此它也会获取相同的记录并开始处理它们。这当然是一个糟糕的情况。在Oracle中,您可以使用SELECT FOR UPD

我在这里看到了一个关于这个问题的问题,但它是旧的,所以我将再次询问,以防现在存在一个解决方案

我的问题是这个。我有一个数据库表,我想从中选择,但我想锁定我选择的行。这样做的原因是,我可能有另一个进程正在运行,该进程也希望选择相同的行,我希望防止这种情况发生

假设我有两个进程在做同一件事。执行选择并开始对数据进行处理。几秒钟后,下一个进程出现并执行select,但由于行未被锁定,因此它也会获取相同的记录并开始处理它们。这当然是一个糟糕的情况。在Oracle中,您可以使用SELECT FOR UPDATE,这将锁定行,以防止第二个进程使用它们。如何在SQL Server 2008中实现这一点


我应该补充一点,我只能使用标准的sql语句。我无法访问程序、函数等。必须通过简单的语句来完成。这是一个很长的故事,一个设计上的考虑已经从我手中夺走了。解决方案必须能够存储在表中,稍后检索,然后通过C中的ADO对象运行,特别是分配给命令对象的ADO对象

如何将锁应用于此语句

SELECT * 
FROM 
  (SELECT TOP (20) * 
   FROM [TMA_NOT_TO_ENTITY_QUEUE]  
   WHERE [TMA_NOT_TO_ENTITY_QUEUE].[STATE_ID] = 2 
   ORDER BY TMA_NOT_TO_ENTITY_QUEUE.ID) a

您应该将流程包装在事务中,并适当地设置事务隔离级别,即:Serializable

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRAN
     UPDATE yourtable...
     -- process 1
COMMIT TRAN

这种行为自古以来就存在于SQL Server中


其他事务隔离级别也可用

通过锁定,您希望第二个进程发生什么?如果您想让它等到第一次完成,完全可以使用事务隔离级别来完成

尝试运行此小测试,您将了解:

在SSMS上打开两个新查询,从现在起将其称为a和B,然后在a上创建一个简单的表,如下所示:

create table transTest(id int)
insert into transTest values(1)
现在,请执行以下操作:

在这两种情况下都要从transTest中选择*。您将看到值1

跑步时:

set transaction isolation level read committed
select * from transTest
在B运行时:

begin transaction
insert into transTest values(2)
commit transaction
跑步时:

set transaction isolation level read committed
select * from transTest
您将看到查询无法完成,因为它被B上的事务锁定

在B运行时:

begin transaction
insert into transTest values(2)
commit transaction
返回到A,您将看到查询已完成


在上设置事务隔离级别为read uncommitted的情况下重复测试,您将看到查询不会被事务锁定

您需要使用一个所谓的:

更新锁阻止其他进程尝试更新或删除有问题的行,但不阻止读取访问:

    SELECT TOP (20) * 
    FROM [TMA_NOT_TO_ENTITY_QUEUE] WITH (UPDLOCK)
    WHERE [TMA_NOT_TO_ENTITY_QUEUE].[STATE_ID] = 2 
    ORDER BY TMA_NOT_TO_ENTITY_QUEUE.ID

还有一个独占锁,但基本上,更新锁应该足够了。一旦您选择了具有更新锁的行,这些行将受到保护,以防更新和写入,直到事务结束。

SQL Server和Oracle的锁定机制完全不同,甚至行为完全相反。如果在代码中包含任何事务级控制元素,那么它就不会是数据库不可知的,但无论如何,没有任何合理复杂度的数据库代码是数据库不可知的。在这种情况下,您必须只使用普通SQL,并保持在SQL92规范内,在应用程序端控制事务,而不使用SQL链接,但这将限制您编写有效的特定于数据库的解决方案的能力

我应该补充一点,我只能使用标准的sql语句。我无法访问程序、函数等。必须通过简单的语句来完成。这是一个很长的故事,一个设计上的考虑已经从我手中夺走了。我将把这些信息添加到我的初始问题中。@csharpend您可以通过SqlConnection.BeginTransaction或System.Transactions命名空间在C代码中初始化事务,具体取决于您的基础结构-并在该语句中设置Data.IsolationLevel-例如,请参见Oracle或其他应用程序的事务是否也一样数据库?我只是问,因为我的解决方案被设计成与数据库无关,所以我不能硬编码任何特定于数据源的内容。我又做了一个决定:你可以使用-select*from tbl updlock通常使用-updlock或xlock hint-updlock,但这取决于具体的任务。这如何应用于我添加到问题中的陈述?在看到你的最终编辑后,使用nowait在发现资源被锁定后立即返回:从tbl updlock中选择*nowait谢谢我会尝试一下,谢谢你的回复。我希望第二个进程不被允许访问。我不希望它等待第一个进程释放锁。例如,我希望它返回一个资源繁忙异常,这样我就可以自己处理它,然后等待一两分钟再次运行该进程。我已经在上面添加了我的select。似乎你把WITH子句放错了位置,它应该在FROM部分。