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
)
一切正常。但有时在核心服务器上,我在 Receipts
和 ReceiptGoodsStrings
中有重复的行。这种情况很少发生,我不明白为什么。
也许我选择了错误的数据传输方式?
看来是并发问题
有可能打开两个并发事务并且都从您的 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
编辑
最后,注意调用同步事务的时间间隔。可能是间隔时间太短,新的交易开始的时候,交易还没有结束。在这种情况下,您可以期望获得重复的行,因为。您可以尝试增加间隔。
我有 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
)
一切正常。但有时在核心服务器上,我在 Receipts
和 ReceiptGoodsStrings
中有重复的行。这种情况很少发生,我不明白为什么。
也许我选择了错误的数据传输方式?
看来是并发问题
有可能打开两个并发事务并且都从您的 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
编辑
最后,注意调用同步事务的时间间隔。可能是间隔时间太短,新的交易开始的时候,交易还没有结束。在这种情况下,您可以期望获得重复的行,因为。您可以尝试增加间隔。