锁如何在insert ... select语句中起作用?

时间:2013-08-06 19:45:58

标签: sql sql-server tsql

两个会话中的两个交易在同一项目上运作:

在第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

如果是这样的话,两个相同的行将插入表中的订单。但我希望先在任一会话中执行事务,然后另一个事务可以读取新的max(OrderNumber)然后插入下一个值。我将holdlock添加到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语句然后为insert语句分配独占锁?在两个会话中,确切的锁如何相互作用?感谢任何提示

3 个答案:

答案 0 :(得分: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 

Serializable选项将提供以下交易功能:

  1. 语句无法读取已修改但尚未由其他事务提交的数据
  2. 在当前事务完成之前,没有其他事务可以修改当前事务已读取的数据
  3. 在当前事务完成之前,其他事务无法插入具有键值的新行,这些键值将落在当前事务中任何语句读取的键范围内。
  4. 以上将适用于您的问题,但我建议使用标识列而不是max ordernumber + 1逻辑。因此,将OrderNumber更改为表中的标识,当您读取数据时,使用row_number编号按运行时按项计算订单编号,这是一个示例查询:

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

    因此上述查询将提供您需要的结果。

答案 1 :(得分:0)

你的最终目标是什么?我不认为你不能阻止选择锁定的插入,它只会锁定任何更新中的选定行。

答案 2 :(得分:0)

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

Second Link。如果这些没有帮助那么请告诉我,以便我可以进一步帮助你。