【问题标题】:How to properly manage collections in SQL Server如何在 SQL Server 中正确管理集合
【发布时间】:2012-12-06 23:32:50
【问题描述】:

假设房屋有居住者,并且任何房屋的两个居住者都不能具有相同的高度。

  1. 随机选择房子
  2. 获取房屋当前居住者的列表
  3. 通过检查列表来决定保留、替换、驱逐或添加哪些内容
  4. 确保新列表不包含任何身高相同的居住者。
  5. 用新列表替换现有列表;根据需要删除、插入或更新。

听起来很简单,但是当您有 50 个线程都尝试同时执行此操作时,它会变得复杂。我在选择(步骤 2)上使用了 UPDLOCK、ROWLOCK 来阻止对我可能想要更新的任何居住者的可能更新。但是,当没有当前居住者并添加了新居住者时,我偶尔会遇到故障。失败始终是唯一的约束违规。这绝不应该发生(参见步骤 4),但它确实发生了。

步骤 2-5 正在使用 ReadCommitted 隔离级别在 TransactionScope 内执行。

是否有最佳实践模型来定义应如何处理此类场景?

【问题讨论】:

  • >通过检查列表来决定保留、替换、驱逐或添加哪些基于什么?我明白驱逐
  • 房子可以没有人吗?

标签: sql locking sql-server-2008-r2 transactionscope transaction-isolation


【解决方案1】:

看看transaction isolation levels in SQL Server。听起来您的问题很可能是您进行了幻读(即,有人将数据插入到您已经选择的范围内)。

在这种情况下具有高级别的并发性,我绝对建议您在具有隔离级别的单个事务中运行所有关联的查询(即,SELECT 后跟适当的 INSERT/UPDATE/DELETE)设置为可序列化。这样,SQL Server 将确保事务彼此完全隔离。

但是,在这种情况下,考虑到它的高度并发性,最好的解决方案可能是在您的代码中实现某种锁定/同步,而不是仅仅依靠 SQL Server 为您完成。 (不过,我仍然建议使用 Serializable 隔离级别。)

例如,使用某种锁管理器为每个居住者和房屋生成一个锁定对象,这样您将始终为同一个居住者(或房屋)获取相同的对象,并让每个线程使用该对象进入临界区(或类似 C# 的 Monitor.Enter) - 请注意避免死锁。这样,您就可以保证在任何给定时间只有一个线程正在检查任何特定的房屋或任何特定的居住者,但仍然允许其他线程运行。

【讨论】:

    【解决方案2】:

    我意识到这不是与 SQL 或 TransactionScope 相关的问题。我正在协调数据项的集合,并且在发生这种情况时必须对集合的访问进行信号化。就我而言,我只需要在进行协调的代码周围添加一个 lock(List) { 。 }

    继续进行类比,如果您要核对一份居住者名单,最好锁上门以防止居住者在您执行此操作时进出。

    【讨论】:

      猜你喜欢
      • 2019-07-31
      • 1970-01-01
      • 1970-01-01
      • 2017-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-14
      • 2018-08-22
      相关资源
      最近更新 更多