SQL 服务器:分布式事务和重复行

SQL Server : distributed transaction and duplicated rows

我有 1 个核心 SQL 服务器和许多将数据传输到核心服务器的辅助 SQL 服务器。

每个辅助 SQL 服务器都有链接的核心服务器和不时运行的存储过程。

这是存储过程中的代码(删除了一些字段,但并不重要)

BEGIN DISTRIBUTED TRANSACTION

SELECT TOP (@ReceiptsQuantity) 
    MarketId, CashCheckoutId, ReceiptId, GlobalReceiptId
INTO #Receipts 
FROM dbo.Receipt
WHERE Transmitted = 0

SELECT ReceiptId, Barcode, GoodId
INTO #ReceiptGoodsStrings
FROM ReceiptGoodsStrings
WHERE ReceiptGoodsStrings.ReceiptId in (SELECT ReceiptId FROM #Receipts)

INSERT INTO [SyncServer].[POSServer].[dbo].[Receipt] 
    SELECT * FROM #Receipts

INSERT INTO [SyncServer].[POSServer].[dbo].[ReceiptGoodsStrings] 
    SELECT * FROM #ReceiptGoodsStrings

UPDATE Receipt 
SET Transmitted = 1 
WHERE ReceiptId in (SELECT ReceiptId FROM #Receipts)

DROP TABLE #Receipts 
DROP TABLE #ReceiptGoodsStrings 

COMMIT TRANSACTION

有两个表:Receipts有很多ReceiptGoodsStrings(键ReceiptID

一切正常。但有时在核心服务器上,我在 ReceiptsReceiptGoodsStrings 中有重复的行。这种情况很少发生,我不明白为什么。

也许我选择了错误的数据传输方式?

看来是并发问题

有可能打开两个并发事务并且都从您的 Receipt table 中读取。每个会话都将写入其自己的临时 tables(#Receipts#ReceiptGoodsStrings)。最后,客户端间歇性地锁定 [SyncServer].[POSServer].[dbo].[Receipt][SyncServer].[POSServer].[dbo].[ReceiptGoodsStrings] 以将临时 table 中的行填充到目标,并且它们都执行更新。

因此,两个事务都已成功完成并且您有重复的行!

幸运的是,您可以在 Receipt table 的第一个 select 上使用 UPDLOCK 提示来锁定您在事务中已经阅读的 rows/pages。另一个客户端将不得不等待第一个执行 COMMIT 的客户端释放锁。然后,第二个将继续,只读取要传输的新行并仅复制它们。

SELECT TOP (@ReceiptsQuantity) 
    MarketId, CashCheckoutId, ReceiptId, GlobalReceiptId
INTO #Receipts 
FROM dbo.Receipt WITH (UPDLOCK)
WHERE Transmitted = 0

编辑

最后,注意调用同步事务的时间间隔。可能是间隔时间太短,新的交易开始的时候,交易还没有结束。在这种情况下,您可以期望获得重复的行,因为。您可以尝试增加间隔。