0

两个会话中的两个事务在同一项目上运行:

在会话 1 中:

begin tran T1

   insert into Invoice with (item,OrderNumber) 

    select 'ItemA', max(OrderNumber)+1 

    from Orders

    where item='ItemA'

    waitfor delay '00:00:05'

commit T1

在会话 2 中:

begin tran T2

   insert into Invoice with (item,OrderNumber) 

    select 'ItemA', max(OrderNumber)+1 

    from Orders

    where item='ItemA'

commit T2

如果像这样,两个相同的行将被插入到表 Orders 中。但我想在任一会话中先完成事务,然后另一个事务可以读取新的 max(OrderNumber),然后插入下一个值。我将保持锁添加到 T1 为:

begin tran T1

   insert into Invoice with (item,OrderNumber) 

    select 'ItemA', max(OrderNumber)+1 

    from Orders with (holdlock)

    where item='ItemA'

    waitfor delay '00:00:05'

commit T1

SQl SERVER 是否首先将共享锁分配给 select,因为它首先解析 select 语句,然后将排他锁分配给 insert 语句?在两个会话中,锁究竟是如何相互工作的?感谢您的任何提示

4

3 回答 3

1

您可以为您的事务使用可序列化的隔离级别。

前任:

 set transaction isolation level serializable
 begin tran
    insert into Invoice with (item,OrderNumber) 
    select 'ItemA', max(OrderNumber)+1 
    from Orders
    where item='ItemA'

    waitfor delay '00:00:05'

 commit tran 

可序列化选项将提供以下事务功能:

  1. 语句无法读取已被其他事务修改但尚未提交的数据
  2. 在当前事务完成之前,其他事务不能修改当前事务已读取的数据
  3. 在当前事务完成之前,其他事务不能插入键值落在当前事务中的任何语句读取的键范围内的新行。

以上将解决您的问题,但我建议使用标识列而不是 max ordernumber + 1 逻辑。因此,将 OrderNumber 更改为表中的标识,当您读取数据时,使用 row_number number 在运行时按 Item 计算订单号,这是一个示例查询:

  select Item, Row_Number() over(partition by Item order by OrderNumber) as OrderNumber
  from Invoice

所以上面的查询会给出你需要的结果。

于 2013-08-06T20:26:50.957 回答
0

你的最终目标是什么。我认为您不能通过锁定选择来停止插入,它只会锁定所选行以防止任何更新。

于 2013-08-06T19:52:49.530 回答
0

数据库锁定方案是任何数据库管理应用程序的组成部分。对于存储在数据库中的数据的完整性,不同的数据库供应商提供了不同的锁定方案。您应该检查以下链接First Link

第二个链接。如果这些没有帮助,请告诉我,以便我可以进一步帮助您。

于 2013-08-06T20:27:53.750 回答