【问题标题】:"Pop" Record -- Select And Delete In The Same Statement (SQL Server 2005)“弹出”记录——在同一语句中选择和删除 (SQL Server 2005)
【发布时间】:2012-03-22 17:27:05
【问题描述】:

我有一个 C# 应用程序,大约有十几个员工同时使用它。它只是从 SQL Server 2005 表中选择顶部记录,删除它,然后在表单上显示数据。
一旦选择了记录,就需要将其删除,因此 2 个人不要抓取并处理同一记录。
相当直截了当......

我不久前发现了一个建议(找不到我从中获得它的网站,抱歉)在同一条语句中执行 SELECT 和 DELETE 并使用此“执行 SqlCommand.ExecuteReader()复合”语句:

SELECT TOP 1 * 
FROM Call_Table 
WHERE Call_Table.hold_call_till <= GetDate() 
ORDER BY Call_Table.attempts ASC, Call_Table.custno ASC;
DELETE 
FROM Call_Table
WHERE Call_Table.custno = (SELECT TOP 1 Call_Table.custno 
                           FROM Call_Table 
                           WHERE Call_Table.hold_call_till <= GetDate() 
                           ORDER BY Call_Table.attempts ASC, Call_Table.custno ASC);

到目前为止,它运行得很好,但我觉得我很幸运。我们正在招聘大约 5 名新人,我想完全确定这将继续有效。

我很想听听该领域更多经验丰富的兽医的意见。

我应该坚持“如果它没有损坏,就不要修复它”的方法吗?或者我应该加强我的游戏并使用某种记录锁或存储过程??

任何建议都将被公开接受。如有必要,我可以提供有关表或 C# 应用程序的更多信息。

【问题讨论】:

标签: c# sql sql-server-2005


【解决方案1】:

我建议改用某种optimistic concurrency control。不要删除记录,而是存储将在选择时获取的时间戳(或其他一些版本控制技术)。然后,如果用户编辑某些内容,您可以检查以确保时间戳没有更改。如果有,则提示用户并重新加载新数据。如果没有,则保存数据,并更新时间戳,这样任何其他拥有数据的人都不会覆盖您的更改。

Microsoft's article on optimistic concurrency

这是我的图形示例版本(使用编号系统而不是时间戳进行版本控制)

Name|PhoneNum|Version
Joe |123-1234|1
  • UserA 和 UserB 在您的 UI 中提取 Joe 的数据

  • UserA 修改并保存 Joe

现在表格如下所示:

Name|PhoneNum|Version
Joe |555-5555|2
  • UserB 修改了 Joe 的数据的版本 1 并保存。保存后看到 Version 现在是 2 并提示 UserB 数据已更改。

更新

如果在用户阅读该行时无法访问该行,您有两种选择。

  • 你可以做你已经在做的事情,但你不需要选择...删除,因为OUTPUT(如上所述)。有了这个,你可以删除并获取值。

代码:

DECLARE @CallInfo TABLE (/*Call_Table Schema*/)

DELETE Call_Table
OUTPUT DELETED.* INTO @CallInfo 
WHERE Call_Table.custno = (SELECT TOP 1 Call_Table.custno 
                       FROM Call_Table 
                       WHERE Call_Table.hold_call_till <= GetDate() 
                       ORDER BY Call_Table.attempts ASC, Call_Table.custno ASC)

--The @CallInfo will have the info that you just deleted, so pass that back to the UI
SELECT * FROM @CallInfo
  • 您可以添加一个锁定列(使用锁定人员的用户 ID),然后在选择数据之前更新该列。如果用户崩溃或做了一些他们没有重置锁的事情,那么你唯一需要担心的是。我过去使用过这个系统,但如果大部分时间数据都被删除,那么复杂性可能不值得。如果您需要简单地更新数据,我发现这更有用。您可以添加逻辑,如果同一用户尝试再次获取数据,则让他们再次获取数据,因为这可能是崩溃。否则,您需要创建一个解锁系统。

【讨论】:

  • 这在我看来就像 2 个以上的用户可以访问同一行。乐观锁仅在记录被更改后才会影响它。 “下午 1:01,User2 读取同一行。”我不能让 2 个用户抓取相同的记录。
  • 为什么不能让两个用户抓取相同的记录?乐观并发将确保值在任何编辑可以被持久化之前是有效的。
  • 当他们抓取记录时,他们会打电话给客户。如果 2 ppl 抓取相同的记录,他们都会打电话给同一个人。我试图思考这如何工作。也许一旦他们抓住它就改变记录。但这给我们留下了选择和更新之间的潜在“差距”。我们可以只删除而不是更新..
  • 通话后会发生什么?记录是否会被删除或使用不同的数据重新输入?这里有两种可能。
  • (小背景)。我们的客户是 3 个月的供应周期。当他们的物资应该用完时,我们会打电话给他们。如果我们打电话,他们需要更多补给品,他们就会从桌子上移开。如果我们打电话但没有得到答复或类似的情况,他们将在稍后的“hold_call_till”时间重新排队。
【解决方案2】:

似乎您需要的是提示 UPDLOCK 加上 READPAST 提示,如此处所述 http://www.adathedev.co.uk/2010/03/queue-table-processing-in-sql-server.html

【讨论】:

    【解决方案3】:

    您可以使用DELETE statementOUTPUT clause 删除一行并在同一语句中返回,例如:

    delete queue output deleted.* where id = (select min(id) from queue)
    

    假设您有一个看起来像这样的表格

    create table Queue(
        ID bigint identity not null primary key,
        Data varchar(max)
    )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-21
      • 1970-01-01
      • 2020-12-16
      • 1970-01-01
      相关资源
      最近更新 更多