“TransactionInDoubtException”exception导致我的事务的完整性丢失

我有一个代码尝试插入作用于MSDTC事务的条目,如果有插入失败,则重试插入到特定阈值。

这是代码:

while(!SaveToDb){ ....... Thread.Sleep(TimeSpan.FromMinutes(AppConfiguration.RetryInsertionDuringFailureIntervalInMin)); } private bool SaveToDb() { try { ...... using (var scope = new TransactionScope(TransactionScopeOption.Required, option)) { Context.SaveEmail(_emailInfoList); Context.SaveSyncState(syncState); scope.Complete(); return true; } } catch (Exception ex) { ........ return false; } } 

并且遇到了这个exception:

消息:该交易存在疑问。 堆栈跟踪:System.Transactions.TransactionStatePromotedIndoubt.PromotedTransactionOutcome(InternalTransaction tx),位于System.Transactions.CommittableTransaction.Commit(),位于System.Transactions.TransactionScope.InternalDispose(),位于System.Transactions.TransactionScope.Dispose(),位于Presensoft.Exchange2010Puch。 Core.PushJob.SaveEmailAndSyncState()InnerException:System.Data.SqlClient.SqlException(0x80131904):超时已过期。 操作完成之前经过的超时时间或服务器没有响应。 —> System.ComponentModel.Win32Exception(0x80004005):在System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning的System.Data.SqlClient.SqlInternalConnection.OnError(SqlExceptionexception,布尔breakConnection,Action`1 wrapCloseInAction)中等待操作超时(TdsParserStateObject stat eObj,Boolean callerHasConnectionLock,Boolean asyncClose)System.Data.SqlClient.TdsParserStateObject.ReadSniSyncOverAsync()上的System.Data.SqlClient.TdsParserStateObject.ReadSniError(TdsParserStateObject stateObj,UInt32错误)
在System.Data.SqlClient.TdsParserStateObject.TryReadNetworkPacket()
在System.Data.SqlClient.TdsParserStateObject.TryPrepareBuffer()at System.Data.SqlClient.TdsParserStateObject.TryReadByte(Byte&value)
在System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior,SqlCommand cmdHandler,SqlDataReader dataStream,BulkCopySimpleResultSet bulkCopyHandler,TdsParserStateObject stateObj,Boolean&dataReady)处于System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior,SqlCommand cmdHandler,SqlDataReader dataStream,BulkCopySimpleResultSet) system.Data.SqlClient.SqlInternalConnectionTds中的System.Data.SqlClient.TdsParser.TdsExecuteTransactionManagerRequest(Byte []缓冲区,TransactionManagerRequestType请求,字符串transactionName,TransactionManagerIsolationLevel isoLevel,Int32超时,SqlInternalTransaction事务,TdsParserStateObject stateObj,布尔值isDelegateControlRequest)中的bulkCopyHandler,TdsParserStateObject stateObj) System.Data.SqlClient.SqlDelegatedTransaction.SinglePhaseComm中的.ExecuteTransactionYukon(TransactionRequest transactionRequest,String transactionName,IsolationLevel iso,SqlInternalTransaction internalTransaction,Boolean isDelegateControlRequest) 它(SinglePhaseEnlistment登记)

此应用程序尝试重新插入条目后,以下内容是

System.Data.SqlClient.SqlException(0x80131904):违反PRIMARY KEY约束’pk_email’。

它在我看来,没有transaction.commit()成功启动(部分)提交已经发生在第一种情况(MSDTCexception),这导致后一个exception。

有没有什么办法可以确定在“事务存在疑问”exception时是否发生了提交,如果存在则回滚提交。

根据MSDN

在对有疑问的事务尝试操作时抛出此exception。 当无法确定交易状态时,交易存在疑问。 具体而言, 交易的最终结果,无论是提交还是中止,都不为此交易所知。

当尝试提交事务并且事务变为InDoubt时,也会抛出此exception。

这是一个可恢复的错误。

编辑:

对于恢复:您必须捕获TransactionInDoubtException并使用apt检查编写补偿逻辑。

 using (var scope = new TransactionScope(TransactionScopeOption.Required, option)) { try { Context.SaveEmail(_emailInfoList); context.SaveSyncState(syncState); scope.Complete(); return true; } catch (TransactionInDoubtException ex) { //check whether any one record from the batch has been partially committed . If committed then no need to reprocess this batch. // transaction scope should be disposed first . scope.Dispose(); if (IsReprocessingNeeded(syncState)) throw; return true; } } ///  private bool IsReprocessingNeeded(SyncStateDataModal syncState) { while (true) { try { var id = _emailInfoList[0].ID; bool isEmailsCommitted = Context.GetJournalEmail().FirstOrDefault(a => a.ID == id) != null; if (!isEmailsCommitted) return true; if (context.EmailSynch(syncState.Id) == null) { context.SaveSyncState(syncState); } return false; } catch (Exception ex) { Thread.Sleep(TimeSpan.FromMinutes(AppConfiguration.RetryConnectionIntervalInMin)); } } } 

消息来源 TransactionInDoubtException的恢复路径是什么?