简体   繁体   English

如何在SQL Server中正确管理集合

[英]How to properly manage collections in SQL Server

Assume that houses have occupants and that no two occupants of any house can have the same height. 假定房屋有住户,并且任何房屋的两个住户都不能具有相同的高度。

  1. Pick a random house 选择一个随机的房子
  2. Get a list of the current occupants of the house 获取房子的当前居住者名单
  3. Decide which ones to keep, replace, evict, or add by examining the list 通过检查列表来确定要保留,替换,驱逐或添加的项目
  4. Make sure that the new list doesn't contain any occupants of the same height. 确保新列表不包含任何身高相同的乘客。
  5. Replace the existing list with the new list; 用新列表替换现有列表; delete, insert, or update as required. 根据需要删除,插入或更新。

Sounds simple enough but when you have 50 threads all trying to do this at the same it gets complicated. 听起来很简单,但是当您有50个线程同时尝试执行此操作时,它将变得很复杂。 I used UPDLOCK, ROWLOCK on the select (step 2) to block possible updates to any of the occupants I might want to update. 我在选择(第2步)上使用了UPDLOCK,ROWLOCK来阻止对我可能要更新的任何乘员的可能更新。 I get an occasional failure, however, when there are no current occupants and a new occupant is added. 但是,当没有当前乘员并添加了新乘员时,我偶尔会失败。 The failure is always a unique constraint violation. 失败始终是唯一的约束冲突。 This should never happen (see step 4) but it does. 这永远都不会发生(请参阅步骤4),但确实会发生。

Steps 2-5 are being performed within a TransactionScope using ReadCommitted isolation level. 正在使用ReadCommitted隔离级别在TransactionScope中执行步骤2-5。

Is there a best practices model somewhere that defines how a scenario like this should be handled? 某个地方是否有最佳实践模型来定义应如何处理这种情况?

Take a look at the transaction isolation levels in SQL Server . 看一下SQL Server中的事务隔离级别 It sounds like your problem is likely that you're having phantom reads (ie, somebody is inserting data into a range that you've already SELECT'ed). 听起来您的问题很可能是幻像读取(即有人正在将数据插入到您已经选择的范围中)。

With a high-level of concurrency in a situation like this, I'd definitely recommend that you run all of the associated queries (ie, SELECT followed by appropriate INSERT/UPDATE/DELETE's) in a single transaction with the isolation level set to Serializable. 在这种情况下,如果具有高级别的并发性,我绝对建议您在隔离级别设置为Serializable的单个事务中运行所有关联的查询(即SELECT,然后进行适当的INSERT / UPDATE / DELETE) 。 That way, SQL Server will ensure that the transactions happen in complete isolation from each other. 这样,SQL Server将确保事务彼此完全隔离地进行。

However, the best solution in this case, given its high degree of concurrency, is probably going to be to implement some sort of locking/synchronization in your code, rather than only relying on SQL Server to do it for you. 但是,鉴于这种情况的最佳并发度,这种情况下的最佳解决方案可能是在代码中实现某种锁定/同步,而不是仅仅依靠SQL Server来完成。 (Although, I'd still recommend using the Serializable isolation level.) (尽管如此,我仍然建议使用可序列化隔离级别。)

For example, use some sort of lock-manager that generates a lock-object for each occupant and house in such a way that you'll always get the same object for the same occupant (or house), and have each thread use that object for entering a critical section (or something similar C#'s Monitor.Enter ) - just be careful to avoid deadlocks. 例如,使用某种锁管理器,它以这样一种方式为每个乘员和房屋生成一个锁对象,即始终为同一乘员(或房屋)获得相同的对象,并使每个线程都使用该对象输入关键部分(或类似C#的Monitor.Enter )的方法-请注意避免死锁。 That way, you guarantee that only one thread is examining any particular house or any particular occupant at any given time, but still allows other threads to run. 这样,您可以确保在任何给定时间只有一个线程正在检查任何特定的房屋或任何特定的占用者,但仍允许其他线程运行。

I've realized that this isn't a SQL or TransactionScope related issue. 我已经意识到这不是与SQL或TransactionScope相关的问题。 I am reconciling a collection of data items and access to the collection must be semaphored while that's happening. 我正在协调数据项的集合,并且在发生这种情况时必须对访问该集合进行信号处理。 In my case, I just needed to add a lock(List) { around the code that does the reconciliation. 就我而言,我只需要在执行对帐的代码周围添加一个lock(List){。 } }

To continue the analogy, if you're going to reconcile a list of occupants, it's probably a good idea to lock the doors to prevent occupants from getting in or out while you're doing it. 继续进行类比,如果您要调和人员列表,则锁定门以防止人员在进出时进出可能是一个好主意。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM