我们的 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 的更改将被提交,消息也会发布到队列中
When MethodThatReadsFromTableX()
从表 X 读取我希望更改存在(在第一个会话完成之前不应创建会话,因为它将无法从队列中获取消息)
我的期望正确吗?可能是什么问题?
以下是我对这个问题的思考。
在分布式事务中,通常使用两阶段提交。在第一阶段,交易协调员要求每个人做好承诺的准备。如果每个人都同意,在第二阶段协调员将命令每个人提交更改。请注意,当节点在此阶段提交更改时,它将不再回滚。另请注意,参与者 A(例如 Sql 服务器)和实际提交更改的参与者 B (MSMQ) 之间可能存在不可避免的间隙。当 MSMQ 已经提交更改时,SQL Server 可能还没有提交(尽管已经收到命令)。
因此,当 MSMQ 提交事务时,没有什么可以阻止创建的消息传递到您的处理器,正如您所说,它在另一个线程中运行。因此,即使在您离开第一个“范围”块之前 - 您的处理器可能会开始处理收到的消息,并且 SQL Servermight尚未提交更改。分布式事务无法阻止这种行为,因为它无法以某种方式强制每个参与者在完全相同的时间完成提交其更改。
长话短说 - 我认为它按预期工作,您应该做好准备,在处理 MSMQ 消息并实现重试逻辑时,可能会丢失所需的数据。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)