How SQL transaction preserves data integrity

时间:2018-03-25 19:48:40

标签: sql sql-server tsql transactions client-server

Let's take a sales server which can sell books to multiple clients.

For example:

  • book { id:1, quantity:10 }
  • book { id:2, quantity:10 }

...and so on

  • client 1 -> Add to Cart of book{id:1,quantity:6}
  • client 2 -> Add to Cart of book{id:1,quantity:7}

When the client clicks the buy button sales server, checks this condition:

if(buy.quantity <= available.quantity) { //available is freshly fetched from db
   sell();
} else {
   fail();
}

Now consider this case:

client2 check this buy condition and is proceeding to sell() method.

Meanwhile client1 also checked the buy condition and finished sell()..

so now available will be only 4

..on the other hand client2 have already passed the buy condition and is halfway executing the sell() condition so after sell() of client2 there will be -3.

How this can be prevented?

How can a transaction help in this case?

2 个答案:

答案 0 :(得分:1)

You need to use a transaction isolation level that will acquire a shared lock when reading the stock level and hold this lock until the update is completed. This blocks the second transaction from running until the first transaction has completed preventing the scenario you discuss.

Have a look at the following Microsoft document for further explanation of the various isolation levels in SQL Server https://docs.microsoft.com/en-us/sql/connect/jdbc/understanding-isolation-levels

答案 1 :(得分:1)

在交易期间需要用户操作时,不应使用显式数据库事务(例如,添加到购物车,结帐)。

通过在自动(单个语句)事务中执行T-SQL中的计算,可以在没有长时间运行的显式事务的情况下避免竞争条件。默认情况下,所有语句都在自动事务中执行。为此,要在并发环境中工作,update语句可以使用乐观并发检查,将从数据库中检索的原始值与当前值进行比较:

UPDATE dbo.Inventory
SET AvailableQuantity -= @BuyQuantity
WHERE ProductCode = @ProductCode
    AND AvailableQuantity = @OriginalAvailableQuantity;
IF @@ROWCOUNT <> 1 RAISERROR(Transaction rejected - someone updated the row',16,1);

rowversion column可以促进乐观并发检查,这在涉及许多列时特别有用:

UPDATE dbo.Inventory
SET AvailableQuantity -= @BuyQuantity
WHERE ProductCode = @ProductCode
    AND RowVersionColumn = @OriginalRowVersionColumn;
IF @@ROWCOUNT <> 1 RAISERROR(Transaction rejected - someone updated the row',16,1);

如果没有乐观并发或过度悲观的锁定,您可以添加数量不能对UPDATE语句产生负面的业务规则。

UPDATE dbo.Inventory
SET AvailableQuantity -= @BuyQuantity
WHERE ProductCode = @ProductCode
    AND AvailableQuantity -= @BuyQuantity >= 0;
IF @@ROWCOUNT <> 1 RAISERROR(Transaction rejected - Available quantity may not be negative',16,1);

这个简化的例子只是为了展示一些乐观的并发技术。当涉及多个语句时(例如,多个项目的全部或全部签出),人们可以而且应该仍然使用显式事务。强大的购物车系统需要考虑放弃或过期的会话以及对可用数量的影响。人们需要根据业务规则添加库存。