4

我正在研究一个拍卖系统,我试图确保我不会受到影响的问题之一是两个人在同一时间为同一项目出价的情况。

为此,我需要锁定表格,获取当前项目的最高出价,确保输入的出价大于该出价,在表格中添加新的出价条目,然后解锁表格。

我需要锁定它,这样第二个网络服务器就不会在我检查最高出价和我将新出价插入表格之间触发出价插入,因为这会导致数据问题。

如何使用 Linq-to-sql 完成此任务?

请注意,我不知道 transactionscopes 是否可以做到这一点,但我不能使用它们,因为由于我们的 webfarm 设置,它们往往会触发分布式事务,而我不能使用分布式事务。

4

3 回答 3

2

在纯 Linq 中实施解决方案似乎存在一些障碍:

  • 你绝对应该避免表锁

表锁会使得在处理一个单一的投标期间不可能对多个项目进行投标,从而严重损害性能

  • Linq to SQL 似乎不支持悲观锁定

如关于SO的其他答案所述。

如果您的代码中不能有事务,我建议您执行以下过程:

  • 为您的操作生成 GUID
  • 使用 guid 伪锁定项目的记录:

    UPDATE Items SET LockingGuid = @guid 
    WHERE ItemId = @ItemId and LockingGuid IS NULL
    
    SELECT @recordsaffected = @@ROWCOUNT
    
  • 如果@@rowcount == 1,则锁定成功

  • 执行您的出价操作
  • 将记录更新回 LockingGuid = NULL

  • 如果锁定失败,则将失败提交给 .Net 客户端,或者使用WAITFOR进行忙碌等待。

您应该实施适当的异常处理,以便项目记录不会被垂死或失败的进程无限期地锁定,可能通过添加一个存储锁定发生的时间戳的日期时间列,并清理孤立的锁。

如果您的架构允许单独的后端操作,您可能需要查看CQRS事件溯源来处理此类投标操作。

于 2012-07-07T23:11:59.363 回答
1

当此处理发生时,您可以使用单独的表来存储信息。例如,您的第二个表可能类似于:

表名:
ItemProcessing

列:
ItemId (int)
ProcessingToken (guid)

当一个进程想要检查当前的出价时,它会将项目的 ID 和一个令牌/guid 写入 ItemProcessing 表。这告诉其他进程当前正在检查该项目。如果 ItemProcessing 表中已经有该项目的行,则其他进程必须等待或中止。原始过程完成后,它会删除令牌(将其设置为 null),或从 ItemProcessing 中完全删除该行。然后其他进程知道他们可以处理该项目。

当然,您需要一种方法来确保两个进程不会同时写入此处理表。您可以通过在 ProcessingToken 为空的表中插入来完成此操作。如果另一个表刚刚击败了一个进程,则第二个进程将无法插入,因为 ProcessingToken 将存在。

虽然不是一个完整的解决方案,但详细地说,这是基本思想。

于 2012-07-07T22:25:17.150 回答
1

您可以手动开始事务并将该事务传递给 DataContext。

http://geekswithblogs.net/robp/archive/2009/04/02/your-own-transactions-with-linq-to-sql.aspx

我认为手动控制连接的打开和关闭也是必要的,以避免不必要的升级到分布式事务。看起来 DataContext 实际上会以自己的方式有时会尝试打开两个连接,从而导致对分布式事务的提升。

于 2012-07-07T23:21:45.217 回答