在sql server中顺序读取

时间:2016-08-03 05:58:49

标签: c# .net sql-server

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

  1. 因为我们在sql server end中没有任何列让我知道是否已经读取了一行。所以我可能在不同的实例中获得相同的价值。
  2. 在我看来,我需要创建一个列来指定是否读取行。 你能推荐一些像MSMQ或Service Broker

    的东西吗?

2 个答案:

答案 0 :(得分:0)

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

  1. 选择和更新应该在一个原子事务中
  2. 如果您的服务提取一些记录进行处理然后崩溃,您将如何将它们返回到数据库
  3. 您可能会遇到死锁,因此您的c#代码应该使用随机等待实现重试
  4. 您可以使用带有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 Service Bus,也可以通过MassTransit API为您提取队列系统的详细信息。

    还有另一种选择,那就是使用SQL Server Service Broker。这种方法的优点是你不需要在MSMQ或其他一些队列系统上引入额外的依赖,你只需要在SQL服务器中启用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/

答案 1 :(得分:0)

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

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

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