AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 315869
Accepted
Fajela Tajkiya
Fajela Tajkiya
Asked: 2022-08-22 05:04:44 +0800 CST2022-08-22 05:04:44 +0800 CST 2022-08-22 05:04:44 +0800 CST

了解 SQL Server 版本存储

  • 772

我正在尝试了解 SQL Server 版本存储和相关的隔离级别。据我了解,当数据库启用读取提交快照选项时,可能会发生这种情况:

  • 一个项目 (id = 1) 在数据库中的价格为 $1000
  • 会话 1 启动更新语句:update products set price = price * 1.5. 由于这涉及表格的所有行,因此需要很长时间。
  • 当update语句仍在进行中时,会话 2 开始查询:select * from products where id = 1。由于数据库处于读取提交快照模式,因此写入者不会阻塞读取者。所以会话 1 从版本商店读取了该行的旧版本,并认为该产品的价格为 1000 美元。
  • session 1的用户觉得价格还不错,所以决定买。但 ...
  • 在用户将产品添加到他的购物车之前,上述update语句执行完毕,产品 (id = 1) 的新价格为 1500 美元。如果用户知道产品的新价格,他就不会购买。

在这种情况下,会发生什么?这种情况真的可能吗?如果是这样,防止这种情况的规范是什么?

sql-server isolation-level
  • 2 2 个回答
  • 413 Views

2 个回答

  • Voted
  1. J.D.
    2022-08-22T05:51:44+08:002022-08-22T05:51:44+08:00

    “在用户将产品添加到他的购物车之前......如果用户知道产品的新价格,他就不会购买。 ” - 这些是发生在应用程序端的事情,与数据库无关,因此从数据库的角度来看,很难回答围绕它们的问题类型。

    这种情况真的可能吗?

    是的,一点没错。

    在这种情况下,会发生什么?

    这取决于您如何编写应用程序。如果应用程序总是从数据库中提取最新数据,因为用户还没有将商品添加到购物车,那么在将商品添加到购物车后,他们将看到 1,500 美元的最新价格。如果您正在使用某种异步应用程序代码,那么您甚至可以在用户当前所在的屏幕上自动更新价格,以便他们在将商品添加到购物车之前看到最新价格。但同样,这些都是独立于数据库层的应用层决策。

    如果是这样,防止这种情况的规范是什么?

    使用悲观的隔离级别,例如 SQL Server 默认的 Read Committed,这将阻止用户在更新完成之前看到价格。

    这实际上是您的两个选项(来自数据库层),要么 1,000 美元(乐观隔离级别)的价格是应用程序查询数据库时的正确价格,要么 1,500 美元(悲观隔离级别)是当时的正确价格。并且使用乐观的隔离级别,更新发生的时间没有什么不正确的,这样价格在用户第一次看到价格之后发生变化。这只是事件的顺序。

    从某种意义上说,它有点像 eBay,商品的价格仅在用户查看该价格时才有效。在之后的任何时刻(例如当用户去购买或竞标该物品时)该价格可能会更改或过期(因为拍卖物品是有时间限制的)。

    • 4
  2. Best Answer
    Charlieface
    2022-08-22T09:51:25+08:002022-08-22T09:51:25+08:00

    您所指的问题称为write skew,并且在使用乐观并发读取和写入数据时发生。

    是的,这在 下是绝对可能的SNAPSHOT,因为版本化数据没有被锁定,并且可以在该隔离级别下读取。这与实际执行的隔离级别无关update products ...,因为正在读取的会话只会转到版本存储。

    为了解决这个问题,一种常见的解决方案是在进行新写入时确认假设(对于实际预订)。新的写入也需要在非SNAPSHOT隔离级别下,并且必须至少是REPEATABLE READ级别(或者您可以一起READCOMMITTEDLOCK使用 a和UPDLOCKtable 提示)。

    因此,您将使用 读取您想要用于 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;
    

    此方法的另一个变体是返回相关rowversion行的值,然后检查(使用与上面相同的事务语义)rowversion是否相同。如果配置,这就是实体框架等 ORM 所做的。

    • 4

相关问题

  • SQL Server - 使用聚集索引时如何存储数据页

  • 我需要为每种类型的查询使用单独的索引,还是一个多列索引可以工作?

  • 什么时候应该使用唯一约束而不是唯一索引?

  • 死锁的主要原因是什么,可以预防吗?

  • 如何确定是否需要或需要索引

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve