Faj*_*iya 5 sql-server isolation-level tempdb-version-store snapshot-isolation
我试图了解 SQL Server 版本存储和相关的隔离级别。据我了解,当数据库启用读取已提交快照选项时,可能会发生这种情况:
update products set price = price * 1.5。由于这涉及表的所有行,因此需要很长时间。update语句仍在进行时,会话 2 启动一个查询:select * from products where id = 1。由于数据库处于读已提交快照模式,因此写入者不会阻止读取者。因此,会话 1 从版本存储中读取该行的旧版本,并认为该产品的价格为 1000 美元。update语句执行完毕,产品(id = 1)的新价格为 1500 美元。如果用户知道产品的新价格,他就不会购买。在这种情况下,会发生什么呢?这种情况实际上可能吗?如果是这样,防止这种情况的规范是什么?
您所指的问题称为写入偏差,当使用乐观并发来读取和写入数据时会发生这种情况。
是的,这在 下绝对是可能的SNAPSHOT,因为版本化数据没有被锁定并且可以在该隔离级别下读取。这与实际执行操作时使用的隔离级别无关update products ...,因为正在读取的会话将仅进入版本存储。
为了解决这个问题,一种常见的解决方案是在进行新写入(针对实际预订)时确认假设。新的写入也需要处于非SNAPSHOT隔离级别下,并且必须至少为REPEATABLE READ级别(或者可以将aREADCOMMITTEDLOCK和UPDLOCK表提示一起使用)。
因此,您可以使用 读取您想要用于 UI 目的的数据SNAPSHOT,这允许用于 UI 目的的非阻塞读取。然后,在实际创建预订时,您将执行以下操作:
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SET XACT_ABORT, NOCOUNT ON;
BEGIN TRAN;
IF @price <> (
SELECT p.price
FROM products p
WHERE p.id = @productId
)
THROW 50001, 'New price detected', 1;
INSERT OrderDetail (....)
VALUES (....);
COMMIT;
Run Code Online (Sandbox Code Playgroud)
此方法的另一个变体是返回rowversion相关行的值,然后检查(使用与上面相同的事务语义)是否rowversion相同。如果配置的话,这就是诸如实体框架之类的 ORM 所做的事情。
| 归档时间: |
|
| 查看次数: |
1556 次 |
| 最近记录: |