【问题标题】:SQL counter increment concurrency issues - The select/update issueSQL 计数器增量并发问题 - 选择/更新问题
【发布时间】:2015-10-16 19:47:25
【问题描述】:

这更像是一个知识分享帖。

最近在我的一个项目中,我遇到了一个很常见的问题,但在我遇到它之前从未真正考虑过它。 有很多可用的解决方案,但不知何故我没有找到我正在寻找的那个,我将在这篇文章中分享。我相信你们中的许多人已经知道以下解决方案,但对于那些不知道的人来说,这绝对可以挽救生命。 :-)

问题:

最近,我正在开发 Windows 服务。该服务应该将一些记录插入到一​​个长期存在并被其他几个旧服务使用的表中。有一列(比如“ID”)包含一个整数值。将 Integer 插入此表的逻辑(可能是几年前)如下所述:

逻辑:

  1. 从表中读取一个值(比如表 1 – 名称/值对),
  2. 将其增加 1
  3. 更新值和
  4. 终于得到新值[/highlight]。

代码

SELECT @value = [Value] from [dbo].[Table1] WHERE [Name] = @Name;
UPDATE [dbo].[ Table1] SET [Value] = @value +1  WHERE [Name] = @Name;
SELECT @value = @value+1;

所使用的技术存在重大并发问题。

  1. 多个线程读取相同的值
  2. 死锁问题

解决此类问题的最佳方法是什么 - 考虑到许多不同的应用程序/服务都提到了这一点?

【问题讨论】:

  • 您能否编辑问题,使其仅包含问题,并使用您的解决方案创建单独的答案?请参阅Can I answer my own question? 了解更多信息。
  • 或许还可以添加一些文档链接,OUTPUT inserted 是什么,这是针对所有 rdbms 还是针对特定的一个?
  • 附件在哪里?
  • 感谢输入,添加附件,添加文档链接并将问题和答案分开..

标签: sql multithreading database-concurrency


【解决方案1】:

决议

显而易见的想法是摆脱这部分并重写它。但有时,特别是当您在这样的领域工作时,某些逻辑、表格、代码已经被其他几个程序引用,这不是一个容易的调用。

我的目标是从根本上解决问题并摆脱它。如果我能做到这一点,应该不会有真正的影响。 proc 的输出将是相同的,因此对于外界来说,实际上没有任何改变。 :-)

因此,我对上述语句进行了一些小调整,以确保每个线程都更新值并读取更新后的值。不再有冲突,不再有脏读。

更新代码

DECLARE @table table(
    Value int NOT NULL
);

-- Update the value and output the same into a local table variable
UPDATE [dbo].[Table1] SET [Value] = [Value] + 1  OUTPUT inserted.[Value] INTO @table
WHERE [Name] = @Name

-- Now read the value from the local table variable
SELECT Value FROM @table;

有关输出子句的更多信息,请查看https://msdn.microsoft.com/en-us/library/ms177564(v=sql.90).aspx

我使用 parallel.foreach 运行了一些测试(20,000 次)。我的测试表有两个条目 -

  1. Name = First 和 Value = 1 - 20,000 次更新后,值应为 20,001
  2. Name = Second,Value = 100 - 20,000 次更新后,值应为 20,100

如果您检查附件,您会发现数字的差异。

死锁问题很难重现,但从测试结果中可以清楚地看出多个线程读取相同值的问题。

欢迎对此提出任何想法。

正如我之前所说,你们中的许多人已经知道这个解决方案,但对于那些不知道的人来说,这绝对可以节省一些时间。 :-)

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-13
相关资源
最近更新 更多