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 / 问题 / 12698
Accepted
ErikE
ErikE
Asked: 2012-02-12 17:06:23 +0800 CST2012-02-12 17:06:23 +0800 CST 2012-02-12 17:06:23 +0800 CST

使用 SELECT-UPDATE 模式时管理并发

  • 772

假设您有以下代码(请忽略它很糟糕):

BEGIN TRAN;
DECLARE @id int
SELECT @id = id + 1 FROM TableA;
UPDATE TableA SET id = @id; --TableA must have only one row, apparently!
COMMIT TRAN;
-- @id is returned to the client or used somewhere else

在我看来,这不是正确管理并发。仅仅因为您有一个事务并不意味着其他人不会读取与您在获取更新语句之前所做的相同的值。

现在,让代码保持原样(我意识到这最好作为单个语句处理,甚至更好地使用自动增量/标识列)有什么方法可以使它正确处理并发并防止允许两个客户端获得相同的竞争条件身份证价值?

我很确定WITH (UPDLOCK, HOLDLOCK)在 SELECT 中添加 a 就可以了。SERIALIZABLE事务隔离级别似乎也可以工作,因为它拒绝任何其他人阅读您所做的事情,直到 tran 结束(更新:这是错误的。请参阅 Martin 的回答)。真的吗?他们会同样工作吗?一个比另一个更受欢迎吗?

想象一下做一些比 ID 更新更合法的事情——一些基于你需要更新的读取的计算。可能涉及许多表,其中一些您会写入,而另一些则不会。这里的最佳做法是什么?

写完这个问题后,我认为锁定提示更好,因为那样你只锁定你需要的表,但我很感激任何人的意见。

PS 不,我不知道最好的答案,真的很想得到更好的理解!:)

sql-server locking
  • 3 3 个回答
  • 14956 Views

3 个回答

  • Voted
  1. Best Answer
    Martin Smith
    2012-02-13T05:35:07+08:002012-02-13T05:35:07+08:00

    只是解决SERIALIZABLE隔离级别方面。是的,这将起作用,但存在死锁风险。

    两个事务都将能够同时读取该行。它们不会相互阻塞,因为它们会根据表结构获取对象S锁或索引RangeS-S锁,并且这些锁是兼容的。但是它们在尝试获取更新所需的锁(分别为对象IX锁或索引RangeS-U)时会相互阻塞,从而导致死锁。

    相反,使用显式UPDLOCK提示将序列化读取,从而避免死锁风险。

    • 12
  2. A-K
    2012-02-12T17:54:33+08:002012-02-12T17:54:33+08:00

    我认为对您来说最好的方法是实际将您的模块暴露给高并发并亲自查看。有时单独使用UPDLOCK就足够了,不需要HOLDLOCK。有时 sp_getapplock 效果很好。我不会在这里做任何笼统的陈述——有时再添加一个索引、触发器或索引视图会改变结果。我们需要对代码进行压力测试,并根据具体情况亲自查看。

    我在这里写了几个压力测试的例子

    编辑:为了更好地了解内部结构,您可以阅读 Kalen Delaney 的书籍。但是,书籍可能会像任何其他文档一样不同步。此外,还有太多的组合需要考虑:六个隔离级别、多种锁、聚集/非聚集索引以及谁知道还有什么。那是很多组合。最重要的是,SQL Server 是闭源的,所以我们不能下载源代码、调试它等等——这将是最终的知识来源。在下一个版本或服务包之后,其他任何内容都可能不完整或过时。

    因此,您不应该在没有自己的压力测试的情况下决定什么对您的系统有效。无论你读过什么,它都可以帮助你理解正在发生的事情,但你必须证明你读过的建议对你有用。我认为没有人可以为你做这件事。

    • 11
  3. Mark Storey-Smith
    2012-02-13T03:46:13+08:002012-02-13T03:46:13+08:00

    在这种特殊情况下,添加UPDLOCK锁SELECT确实可以防止异常。没有必要添加,HOLDLOCK因为在交易期间会持有更新锁,但我承认自己过去将其作为(可能是坏的)习惯包括在内。

    想象一下,做一些比 ID 更新更合法的事情,一些基于你需要更新的读取的计算。可能涉及许多表,其中一些您会写入,而另一些则不会。这里的最佳做法是什么?

    没有最佳实践。您选择的并发控制必须基于应用程序的要求。一些应用程序/事务需要像拥有数据库的独占所有权一样执行,不惜一切代价避免异常和不准确。其他应用程序/事务可以容忍彼此之间的某种程度的干扰。

    • 检索网上商店中产品的带状库存水平(<5、10+、50+、100+)=脏读(不准确无关紧要)。
    • 在该网上商店结账时检查并降低库存水平 = 可重复读取(我们必须在出售之前拥有库存,我们不得以负库存水平结束)。
    • 在我在银行的活期账户和储蓄账户之间转移现金=可序列化(不要误算或放错我的现金!)。

    编辑:@AlexKuznetsov 的评论促使我重新阅读了这个问题并删除了答案中非常明显的错误。在深夜发帖时提醒自己。

    • 9

相关问题

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

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

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

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

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

Sidebar

Stats

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

    如何查看 Oracle 中的数据库列表?

    • 8 个回答
  • Marko Smith

    mysql innodb_buffer_pool_size 应该有多大?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    从 .frm 和 .ibd 文件恢复表?

    • 10 个回答
  • Marko Smith

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

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    如何选择每组的第一行?

    • 6 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

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

    • 4 个回答
  • Marko Smith

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

    • 7 个回答
  • 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
    pedrosanta 使用 psql 列出数据库权限 2011-08-04 11:01:21 +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
  • Martin Hope
    bernd_k 什么时候应该使用唯一约束而不是唯一索引? 2011-01-05 02:32:27 +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