我的交易的完整性因" TransactionInDoubtException"而丢失。例外

时间:2014-04-28 06:52:55

标签: c# sql-server sql-server-2008 transactions msdtc

我有一个代码尝试插入作用于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;
        }
    }

遇到此异常:

  

消息:该交易存在疑问。堆栈跟踪:at   System.Transactions.TransactionStatePromotedIndoubt.PromotedTransactionOutcome(InternalTransaction   tx)在System.Transactions.CommittableTransaction.Commit()at   System.Transactions.TransactionScope.InternalDispose()at   System.Transactions.TransactionScope.Dispose()at   Presensoft.Exchange2010Puch.Core.PushJob.SaveEmailAndSyncState()   InnerException:System.Data.SqlClient.SqlException(0x80131904):   超时已过期。完成之前已经过了超时时间   操作或服务器没有响应。 --->   System.ComponentModel.Win32Exception(0x80004005):等待操作   超时时间   System.Data.SqlClient.SqlInternalConnection.OnError(SQLEXCEPTION   exception,Boolean breakConnection,Action`1 wrapCloseInAction)at   System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject   stat eObj,Boolean callerHasConnectionLock,Boolean asyncClose)at   System.Data.SqlClient.TdsParserStateObject.ReadSniError(TdsParserStateObject   stateObj,UInt32错误)at   System.Data.SqlClient.TdsParserStateObject.ReadSniSyncOverAsync()
  在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,布尔& dataReady)at   System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior,   SqlCommand cmdHandler,SqlDataReader dataStream,   BulkCopySimpleResultSet bulkCopyHandler,TdsParserStateObject   stateObj)at   System.Data.SqlClient.TdsParser.TdsExecuteTransactionManagerRequest(字节[]   buffer,TransactionManagerRequestType请求,String transactionName,   TransactionManagerIsolationLevel isoLevel,Int32超时,   SqlInternalTransaction事务,TdsParserStateObject stateObj,   Boolean isDelegateControlRequest)at   System.Data.SqlClient.SqlInternalConnectionTds.ExecuteTransactionYukon(TransactionRequest   transactionRequest,String transactionName,IsolationLevel iso,   SqlInternalTransaction internalTransaction,Boolean   isDelegateControlRequest)at   System.Data.SqlClient.SqlDelegatedTransaction.SinglePhaseCommit(SinglePhaseEnlistment   征募)

此应用程序尝试重新插入条目后,

  

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

在我看来,没有transaction.commit()成功启动(部分)提交已经发生在第一种情况下(MSDTC异常),这导致了后一种异常。

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

1 个答案:

答案 0 :(得分:1)

根据 MSDN

  

尝试对事务执行操作时抛出此异常   这是有疑问的。当交易的状态时,交易是有疑问的   交易无法确定。具体来说,的最终结果   这项交易,无论是承诺还是中止,都是不可知的   事务。

     

尝试提交时也会抛出此异常   交易和交易变得毫无疑问。

     

这是一个可恢复的错误。

修改

恢复: 你必须抓住TransactionInDoubtException&用适当的检查写补偿逻辑。

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;
        }
    }

        /// <returns></returns>
        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));
                }
            }
        }

消息来源 What is the recovery path for TransactionInDoubtException ?