TransactionScope - 事务性 WCF 和 paralellism/multithreading
TransactionScope - Transactional WCF and paralellism/multithreading
我正在寻找我们项目中的一个错误,我们 有时 看到数据被保存到数据库中,即使发生异常并且一切都应该回滚。我有 ,发现如果我在创建新的 TransactionScope
后立即查询数据库 @@trancount
,结果得到 0
,我没有 "valid"交易。它以某种方式 aborted/rolled 被另一个线程返回。
我用来复现的代码真的很简单:
我在Paralell.For
中调用这个方法几千次
void Handle()
{
try
{
using (var transaction = new TransactionScope(TransactionScopeOption.Required)
{
// Getting @@trancount right here enables us verify whether we have a valid transaction.
WriteImportantBusinessDataToDatabase("This will sometimes be committed even if the WCF call below fails!");
// Making a transactional WCF call
var serviceClient = new Service1Client("WSHttpBinding_IService1");
serviceClient.DoWork(); // We get an exception here
WriteImportantBusinessDataToDatabase("We never reach this location");
transaction.Complete();
}
}
catch (Exception e)
{
Logger.Error(e, "Something failed. {message}", e.Message);
}
}
WCF 服务是事务性的,TransactionFlowOption.Mandatory
。
[ServiceContract]
public interface IService1
{
[OperationContract]
[TransactionFlow(TransactionFlowOption.Mandatory)]
void DoWork();
}
[ServiceBehavior]
public class Service1 : IService1
{
[OperationBehavior(TransactionScopeRequired = true)]
public void DoWork()
{
throw new Exception();
}
}
@@trancount
预计在创建新的 TransactionScope
后立即 1
。但是有时
@@trancount
是 0
,在更罕见的情况下 2
。 System.Transactions.Transaction.Current.TransactionInformation.Status
属性 始终是 Active
,无论 @@trancount
是什么。插入数据库执行得很好。问题发生然后本地事务被 WCF 调用提升为分布式事务。然后我们得到一个异常说 "The transaction has aborted."
方法名称 Handle
正确地表明这确实是一个 NServiceBus 处理程序,日夜处理数十万条消息。仅当 WCF 调用的另一端存在问题时,我们才会遇到此不一致问题。
可以找到此设置的可运行版本 on my GitHub。
我已经重现了从 4.5.1 到 4.8 的所有 .Net 框架版本的问题。所有这些都产生相同的结果。谁能解释一下这里发生了什么?
这是由.Net 的连接共享机制中某处的错误引起的。该错误在 4.5.1 和 4.8 之间的所有 .Net Framework 版本以及新的 System.Data.SqlClient package.
上重现
一个issue has been added to the System.Data.SqlClient repository.
我正在寻找我们项目中的一个错误,我们 有时 看到数据被保存到数据库中,即使发生异常并且一切都应该回滚。我有 TransactionScope
后立即查询数据库 @@trancount
,结果得到 0
,我没有 "valid"交易。它以某种方式 aborted/rolled 被另一个线程返回。
我用来复现的代码真的很简单:
我在Paralell.For
中调用这个方法几千次
void Handle()
{
try
{
using (var transaction = new TransactionScope(TransactionScopeOption.Required)
{
// Getting @@trancount right here enables us verify whether we have a valid transaction.
WriteImportantBusinessDataToDatabase("This will sometimes be committed even if the WCF call below fails!");
// Making a transactional WCF call
var serviceClient = new Service1Client("WSHttpBinding_IService1");
serviceClient.DoWork(); // We get an exception here
WriteImportantBusinessDataToDatabase("We never reach this location");
transaction.Complete();
}
}
catch (Exception e)
{
Logger.Error(e, "Something failed. {message}", e.Message);
}
}
WCF 服务是事务性的,TransactionFlowOption.Mandatory
。
[ServiceContract]
public interface IService1
{
[OperationContract]
[TransactionFlow(TransactionFlowOption.Mandatory)]
void DoWork();
}
[ServiceBehavior]
public class Service1 : IService1
{
[OperationBehavior(TransactionScopeRequired = true)]
public void DoWork()
{
throw new Exception();
}
}
@@trancount
预计在创建新的 TransactionScope
后立即 1
。但是有时
@@trancount
是 0
,在更罕见的情况下 2
。 System.Transactions.Transaction.Current.TransactionInformation.Status
属性 始终是 Active
,无论 @@trancount
是什么。插入数据库执行得很好。问题发生然后本地事务被 WCF 调用提升为分布式事务。然后我们得到一个异常说 "The transaction has aborted."
方法名称 Handle
正确地表明这确实是一个 NServiceBus 处理程序,日夜处理数十万条消息。仅当 WCF 调用的另一端存在问题时,我们才会遇到此不一致问题。
可以找到此设置的可运行版本 on my GitHub。
我已经重现了从 4.5.1 到 4.8 的所有 .Net 框架版本的问题。所有这些都产生相同的结果。谁能解释一下这里发生了什么?
这是由.Net 的连接共享机制中某处的错误引起的。该错误在 4.5.1 和 4.8 之间的所有 .Net Framework 版本以及新的 System.Data.SqlClient package.
上重现一个issue has been added to the System.Data.SqlClient repository.