我有一个代码尝试插入作用于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异常),这导致了后一种异常。
有什么办法可以确定当“事务有疑问”异常时是否发生了提交,如果有则回滚提交。
答案 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 ?