我需要在 15 个表中保存/更新数据。我必须确保在更新时保持并发和锁定,以免发生脏读。我正在使用存储过程更新数据。我可以在 oredr 中做什么来实现锁定和并发?
4 回答
其他答案假设您已经在使用事务。我不会省略这个,因为你可能会错过它。
您应该使用事务来确保插入/更新所有 15 个表中的记录或没有记录。事务确保您在操作中的原子性。如果在存储过程中出现故障并且您不使用事务,则将进行一些保存/更新操作,而另一些则不进行(来自产生错误的查询的操作)。
如果您使用BEGIN TRAN和 COMMIT 成功操作或 ROLLBACK 在失败的情况下,您将全部完成或一无所获。您应该在每次查询执行后检查错误,如果有错误则调用 ROLLBACK TRANSACTION,或者在存储过程结束时调用 COMMIT。
在这个 Stackoverflow 问题的已接受答案中有一个很好的示例,关于如何在存储过程中处理事务。
一旦有了事务,第二部分就是如何避免脏读。您可以将数据库的隔离级别设置为 READ COMMITED,默认情况下,这将防止对数据的脏读。但是用户仍然可以通过在查询中指定WITH (NOLOCK) 或 READUNCOMMITED来选择执行脏读。你无法阻止这一点。
此外,还有一些快照隔离级别(Snapshot 和 Read Commited Snapshot)可以防止锁定(这并不总是好的),同时避免脏读。
互联网上有很多关于这个主题的文献。如果您对快照隔离级别感兴趣,我建议您阅读来自 Brent Ozar 的 Kendra Little 的这篇精彩文章。
您无法阻止脏读不会发生。进行脏读的是读者,而不是你(作者)。您所能做的就是确保您的写入是原子的,这是通过将所有写入包装在一个事务中来完成的。这样,不发出脏读的读者将看到您的所有更新,或者没有(原子)。
如果读者选择发出脏读,则您无能为力。
请注意,更改隔离级别对读者的隔离级别没有任何影响。
您需要做的就是确保正确设置了sql server 隔离级别。为了消除脏读,它需要处于Read Committed或更高,(Not at Read Uncommitted)。Read Committed是开箱即用的默认设置。
但是,查看上面的链接并查看更高设置提供的好处(和后果)可能是值得的。
您可以将事务隔离级别设置为 SERIALIZABLE。通过使用以下语句
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
在您开始交易之前,但警告它可能会减慢其他用户的速度,这些用户将尝试查看更新或将数据插入您的表中,您还可以使用 SNAP_SHOT 隔离级别,它只显示最后提交/保存的数据,但它使Temp DB 的广泛使用也会影响性能。