sql server中的顺序读取

本文关键字:顺序 读取 server sql | 更新日期: 2023-09-27 18:00:01

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

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

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

sql server中的顺序读取

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

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

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

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

  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/.