【问题标题】:Sequential read in sql serversql server 中的顺序读取
【发布时间】:2016-12-08 16:46:41
【问题描述】:

我们有一个从 sql server 读取数据的 .Net 服务。做一些处理,然后再次更新 sql server 表。现在我们需要运行这个服务的多个实例。所以我遇到了以下问题。

  1. 由于我们在 sql server 端没有任何列可以让我知道一行是否已被读取。所以我可能会在不同的情况下得到相同的值。

在我看来,我需要创建一个列来指定一行是否被读取。 你能推荐像 MSMQ 或 Service Broker 这样的东西吗

【问题讨论】:

  • This 听起来很适合您的解决方案
  • 处理部分是发生在 SQL Server 端本身的存储过程中,还是您在选择后将其带到您的 C# 应用程序代码中,然后将其发送回以更新数据库?
  • 请同时粘贴表格架构

标签: c# .net sql-server


【解决方案1】:

您可以考虑创建一个表,例如 ReservedRows 来跟踪正在处理的行,它包含目标表中行的 ID。

然后在服务中,先锁定 ReservedRows 表,然后读取你要处理的数据,排除已经在 ReservedRows 的数据,将你正在读取的记录的 id 插入到 ReservedRows 中,然后解锁表。由于您插入了正在处理的行的 id,因此服务的其他实例在您完成之前不会处理这些。

处理完行并更新目标表后。从 ReservedRows 表中删除您刚刚处理的行的 ID,以便其他实例以后可以处理这些行。

【讨论】:

    【解决方案2】:

    通过服务的多个实例轮询数据库是您需要处理几个问题的选项:

    1. 选择和更新应该在一个原子事务中
    2. 如果您的服务提取了一些记录进行处理然后崩溃,您将如何将它们返回到数据库中
    3. 您可能会遇到死锁,因此您的 c# 代码应实现随机等待的重试

    您可以使用这样的代码通过使用带有 OUTPUT 子句的 UPDATE 语句来进行原子更新/选择:

    DECLARE @fetched TABLE (id INT)
    UPDATE D
    SET D.Processed=1,D.ProcessId=123,D.StartTime=GETDATE()
    OUTPUT inserted.id INTO @fetched
    FROM queueData D
         INNER JOIN (
            SELECT TOP 10 T10.id
            FROM queueData T10
            WHERE T10.Processed=0
            ORDER BY id
         ) Top10 ON D.id=Top10.id
    
    SELECT * FROM @fetched
    

    您可以直接使用 MSMQ 或 Azure 服务总线,也可以通过 MassTransit API 为您提取队列系统的详细信息。

    还有另一种选择,那就是使用 SQL Server Service Broker。这种方法的优点是您不需要引入对 MSMQ 或其他一些队列系统的额外依赖,您只需要在 SQL Server 中启用 Service Broker,然后使用 TSQL 将消息放入队列并从队列中获取消息.此外,SQL Server 会处理事务。

    -- enable the Service Broker
    ALTER DATABASE test SET ENABLE_BROKER
    GO
    
    -- Message Type
    CREATE MESSAGE TYPE TestMessage VALIDATION = NONE
    GO
    
    -- Contract
    CREATE CONTRACT TestContract (TestMessage SENT BY INITIATOR)
    GO
    
    -- Send Queue
    CREATE QUEUE TestSendQueue
    GO
    
    -- Receive Queue
    CREATE QUEUE TestReceiveQueue
    
    -- Create Send Service
    CREATE SERVICE TestSendService ON QUEUE TestSendQueue (TestContract)
    GO
    
    -- Create Receive Service
    CREATE SERVICE TestReceiveService ON QUEUE TestReceiveQueue (TestContract)
    GO
    
    -- Dialog using on contract
    DECLARE @testDialog uniqueidentifier
    DECLARE @Message VARCHAR(128)
    BEGIN DIALOG CONVERSATION @testDialog 
            FROM SERVICE TestSendService
            TO SERVICE 'TestReceiveService'
            ON CONTRACT TestContract
    WITH ENCRYPTION = OFF
    
    -- Send messages
    SET @Message = 'Very First Message';
    SEND ON CONVERSATION @TestDialog MESSAGE TYPE TestMessage (@Message)
    GO
    
    -- Receive messages from Receive Queue
    RECEIVE TOP(1) CONVERT(VARCHAR(MAX), message_body) AS Message
    FROM TestReceiveQueue
    GO
    

    以上代码部分来自http://blog.sqlauthority.com/2009/09/21/sql-server-intorduction-to-service-broker-and-sample-script/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-02
      • 2012-04-01
      • 2021-12-10
      • 1970-01-01
      • 2021-04-20
      相关资源
      最近更新 更多