admin

事务隔离-插入取决于先前的记录值

sql

想象一下我们有常规的Orders_Headers和Orders_LineItems表的情况。还可以说我们有一条特殊的业务规则,其中规定:

  1. 每个订单都有“折扣”字段,该字段是根据上次输入的订单所经过的时间计算得出的

  2. 如果在过去的Y个小时内有超过X个订单,则将特别计算每个下一个订单折扣字段。

  3. 如果最近10个订单的平均频率高于每分钟x,则将特别计算每个下一个订单折扣字段。

  4. 每个下一个订单折扣字段是专门计算的

这里的要点是表明每个订单都依赖于先前的订单,隔离级别至关重要。

我们有一个事务(只是所示代码的逻辑):

BEGIN TRANSACTION

INSERT INTO Order_Headers...

SET @Id = SCOPE_IDENTITY()

INSERT INTO Order_LineItems...(using @Id)

DECLARE @SomeVar INT

--just example to show selecting previous x orders
--needed to calculate Discount value for new Order
SELECT @SomeVar = COUNT(*) Order_Headers
WHERE ArbitraryCriteria

UPDATE Order_Headers
SET Discount= UDF(@SomeVar)
WHERE Id = @Id

COMMIT

END TRANSACTION

我们还有另一笔交易来读取订单:

SELECT TOP 10 * FROM Order_Headers
ORDER BY Id DESC

问题

  1. SNAPSHOT隔离级别是否适用于第一个事务,而READ COMMITED是否适用于第二个适当级别?

  2. 有没有更好的方法来处理CREATE / UPDATE事务,或者这是做到这一点的方法?


阅读 229

收藏
2021-06-07

共1个答案

admin

serializable选项:

通过updlockserializable表提示使用悲观锁定策略来获取由where条件指定的键范围锁定(由支持索引支持以仅锁定查询所需的范围):

declare @Id int, @SomeVar int;
begin tran;

  select @SomeVar = count(OrderDate) 
  from Order_Headers with (updlock,serializable) 
  where OrderDate >= '20170101';

  insert into Order_Headers (OrderDate, SomeVar)
    select sysdatetime(), @SomeVar;

  set @Id = scope_identity();

  insert into Order_LineItems (id,cols)
    select @Id, cols
    from @TableValuedParameter;

commit tran;
2021-06-07