gpt4 book ai didi

c# - 使用 MSMQ 和 SQL Server 的分布式事务,但有时会出现脏读

转载 作者:行者123 更新时间:2023-11-30 23:25:05 25 4
gpt4 key购买 nike

我们的 SQL Server 2014 数据库设置为 READ_COMMITTED_SNAPSHOT

我们使用 MSMQ 和分布式事务(我们使用 MassTransit 2.10)

在我们系统的一部分中,我们从队列中读取一条消息,进行数据库更新,然后将一条新消息发布到队列中(所有这些都在一个事务中)。

我们发现了一种情况,当处理下一条消息时(它从第一部分更新的同一个表中读取)似乎没有提交更新,即使我希望该消息只在队列中同时更新数据库。当我们稍后查询表时,更新的数据如预期的那样存在。这似乎只在我们有高负载时才会发生,而且很少发生。

我们代码的简化版本

// code that processes message 1
using (var scope = new TransactionScope(TransactionScopeOption.RequiresNew, new TransactionOptions() { Timeout = TimeSpan.FromMinutes(30), IsolationLevel = IsolationLevel.ReadCommitted })
{
MethodThatUpdatesTableX();
MethodThatCreatesMessage2();
scope.Complete();
}

// message picked up from MSMQ and then (this runs in different thread):
// code that process message 2
using (var scope = new TransactionScope(TransactionScopeOption.RequiresNew, new TransactionOptions() { Timeout = TimeSpan.FromMinutes(30), IsolationLevel = IsolationLevel.ReadCommitted })
{
MethodThatReadsFromTableX(); // so here it seems that changes made in MethodThatUpdatesTableX is sometimes (though rarely) not read
// other stuff
}

这是我的理解:

处理范围后,将提交对表 X 的更改以及发布到队列的消息

MethodThatReadsFromTableX() 从表 X 读取时,我希望更改在那里( session 不应在第一个完成之前创建,因为它无法接收消息从队列中)

我的期望是否正确?可能是什么问题?

最佳答案

以下是我对这个问题的看法。

在分布式事务中,通常使用两阶段提交。在第一阶段,交易协调员要求每个人准备提交。如果每个人都同意,第二阶段协调员将命令每个人提交更改。请注意,当节点在此阶段提交更改时 - 它不会再回滚。另请注意,参与者 A(例如 Sql 服务器)和参与者 B (MSMQ) 之间可能不可避免地会提交他们的更改。当 MSMQ 已提交更改时,可能是 SQL Server 尚未提交(尽管已被命令提交)。

因此,当 MSMQ 提交事务时,没有什么可以阻止将创建的消息传递给您的处理器,正如您所说,处理器在另一个线程中运行。因此,即使在您离开第一个“范围” block 之前 - 您的处理器可能会开始处理收到的消息,并且 SQL 服务器可能仍未提交更改。分布式事务不能阻止这种行为,因为它不能以某种方式强制每个参与者在完全相同的时间完成提交他们的更改。

长话短说 - 我认为它按预期工作,您应该准备好在处理 MSMQ 消息和实现重试逻辑时可能会丢失所需的数据。

关于c# - 使用 MSMQ 和 SQL Server 的分布式事务,但有时会出现脏读,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37463562/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com