我实施了EF 6执行策略的暂停,无论我需要使用分布式事务来避免"' SqlAzureExecutionStrategy'不支持用户发起的交易"例外,遵循以下示例:
https://romiller.com/2013/08/19/ef6-suspendable-execution-strategy/ https://msdn.microsoft.com/en-us/library/dn307226(v=vs.113).aspx
然而,最近我在批量数据管理会话期间遇到了两次失败,导致最终获得上述异常。
如果我理解正确,给定的示例在全局级别启用/禁用执行策略,这意味着如果在多个线程上同时执行操作,则一个操作可以在另一个操作完成之前结束暂停。如果将.NET 4.6.1用于跨多个SQL Azure DB的事务,则效果可能最明显,这可能需要一段时间才能完成。
为了避免这种情况,我尝试创建一个全局事务计数器,它以线程安全的方式递增和递减,并且只有在没有待处理的事务时才解除挂起,例如:
public class MyConfiguration : DbConfiguration
{
public MyConfiguration()
{
this.SetExecutionStrategy("System.Data.SqlClient", () => SuspendExecutionStrategy
? (IDbExecutionStrategy)new DefaultExecutionStrategy()
: new SqlAzureExecutionStrategy());
}
public static bool SuspendExecutionStrategy
{
get
{
return (bool?)CallContext.LogicalGetData("SuspendExecutionStrategy") ?? false;
}
set
{
CallContext.LogicalSetData("SuspendExecutionStrategy", value);
}
}
}
然后:
public class ExecutionHelper
{
private static int _pendingTransactions;
public void ExecuteUsingTransaction(Action action)
{
SuspendExeutionStrategy();
try
{
using (var transaction = new TransactionScope())
{
action();
transaction.Complete();
}
ResetSuspension();
}
catch (Exception ex)
{
ResetSuspension();
throw ex;
}
}
private void SuspendExeutionStrategy()
{
Interlocked.Increment(ref _pendingTransactions);
MyConfiguration.SuspendExecutionStrategy = true;
}
private void ResetSuspension()
{
Interlocked.Decrement(ref _pendingTransactions);
if (_pendingTransactions < 1 )
{
MyConfiguration.SuspendExecutionStrategy = false;
}
}
}
虽然MSDN上给出的示例没有考虑到这一点,但我仍感到困惑。有没有我忽略的东西?
答案 0 :(得分:2)
<强>更新强>
原则上CallContext是特定于线程的,所以无论如何你都不必担心这个场景中的多线程。 (见备注:https://msdn.microsoft.com/en-us/library/system.runtime.remoting.messaging.callcontext(v=vs.110).aspx)
遇到这种情况的同时,我试图得到类似的东西。
非常确定您的解决方案实际上并不是线程安全的。一个线程仍然可以进入,并在重置递减数字和将暂停设置为false之间将暂停设置为true,这意味着新线程不会将暂停设置为true并且将失败。
你需要一个ReaderWriterLock来确保阻止任何新的线程将暂停设置为true,同时你在reset方法中减少,检查并“甩掉”暂停。像:
private ReaderWriterLock _readerWriterLock = new ReaderWriterLock();
private void SuspendExeutionStrategy()
{
_readerWriterLock.AcquireReaderLock(_timeout);
Interlocked.Increment(ref _pendingTransactions);
MyConfiguration.SuspendExecutionStrategy = true;
_readerWriterLock.ReleaseReaderLock();
}
private void ResetSuspension()
{
_readerWriterLock.AcquireWriterLock(_timeout);
Interlocked.Decrement(ref _pendingTransactions);
if (_pendingTransactions < 1)
{
MyConfiguration.SuspendExecutionStrategy = false;
}
_readerWriterLock.ReleaseWriterLock();
}
答案 1 :(得分:0)
我得到了同样的错误:
" 'SqlAzureExecutionStrategy' does not support user initiated transactions"
我重写了这样的代码并且它有效:
var strategy = _context.Database.CreateExecutionStrategy();
await strategy.ExecuteAsync(async () =>
{
using (var dbContextTransaction = _context.Database.BeginTransaction())
{
// Your code here
dbContextTransaction.Commit();
}
catch (Exception ex)
{
dbContextTransaction.Rollback();
throw;
}
}
});