加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > MsSql教程 > 正文

linq – 如何使用SqlAzureExecutionStrategy和“Nolock”

发布时间:2020-12-12 07:07:21 所属栏目:MsSql教程 来源:网络整理
导读:为了处理SQL超时我正在尝试使用SqlAzureExecutionStrategy( https://msdn.microsoft.com/en-us/data/dn456835.aspx) 我遇到的问题是它阻止了“用户启动的事务”,这似乎是在EF(http://www.hanselman.com/blog/GettingLINQToSQLAndLINQToEntitiesToUseNOLOCK.as
为了处理SQL超时我正在尝试使用SqlAzureExecutionStrategy( https://msdn.microsoft.com/en-us/data/dn456835.aspx)

我遇到的问题是它阻止了“用户启动的事务”,这似乎是在EF(http://www.hanselman.com/blog/GettingLINQToSQLAndLINQToEntitiesToUseNOLOCK.aspx,NOLOCK with Linq to SQL)中实现“with(nolock)”的推荐方法.

示例代码

public AspnetUser GetAspnetUserByUserName(string userName)
    {
        using (var tx = new TransactionScope(TransactionScopeOption.Required,new TransactionOptions() { IsolationLevel = IsolationLevel.ReadUncommitted }))
        {
            return context.AspnetUsers.Where(x => x.UserName == userName).FirstOrDefault();
        }
    }

抛出错误

The configured execution strategy ‘SqlAzureExecutionStrategy’ does not support user initiated transactions. See 07003 for additional information.

我已经看到了在每次调用的基础上关闭SqlAzureExecutionStrategy的答案,但是如果我的所有读取都忽略了策略,那将会破坏使用它的目的.可以同时拥有“NoLock”和SqlAzureExecutionStrategy

解决方法

SqlAzureExecutionStrategy不支持在要重试的操作之外启动的事务.要解决此限制,您需要暂停策略,创建事务范围并将操作作为手动传递给要重试的执行策略的操作:
public AspnetUser GetAspnetUserByUserName(string userName)
{
    new SuspendableSqlAzureExecutionStrategy().Execute(() =>
        {
            using (var tx = new TransactionScope(
                    TransactionScopeOption.Required,new TransactionOptions() { IsolationLevel = IsolationLevel.ReadUncommitted }))
            {
                return context.AspnetUsers.Where(x => x.UserName == userName).FirstOrDefault();
            }
        });
}

在这里,我使用了https://msdn.microsoft.com/en-us/data/dn307226中可挂起策略的替代方法,它将自动挂起任何嵌套调用:

using System.Data.Entity.Infrastructure;
using System.Data.Entity.SqlServer;
using System.Data.Entity.Utilities;
using System.Runtime.Remoting.Messaging;
using System.Threading;
using System.Threading.Tasks;

public class SuspendableSqlAzureExecutionStrategy : IDbExecutionStrategy
{
    private readonly IDbExecutionStrategy _azureExecutionStrategy;

    public SuspendableSqlAzureExecutionStrategy()
    {
        _azureExecutionStrategy = new SqlAzureExecutionStrategy();
    }

    private static bool Suspend
    {
        get { return (bool?)CallContext.LogicalGetData("SuspendExecutionStrategy") ?? false; }
        set { CallContext.LogicalSetData("SuspendExecutionStrategy",value); }
    }

    public bool RetriesOnFailure
    {
        get { return !Suspend; }
    }

    public virtual void Execute(Action operation)
    {
        if (!RetriesOnFailure)
        {
            operation();
            return;
        }

        try
        {
            Suspend = true;
            _azureExecutionStrategy.Execute(operation);
        }
        finally
        {
            Suspend = false;
        }
    }

    public virtual TResult Execute<TResult>(Func<TResult> operation)
    {
        if (!RetriesOnFailure)
        {
            return operation();
        }

        try
        {
            Suspend = true;
            return _azureExecutionStrategy.Execute(operation);
        }
        finally
        {
            Suspend = false;
        }
    }

    public virtual async Task ExecuteAsync(Func<Task> operation,CancellationToken cancellationToken)
    {
        if (!RetriesOnFailure)
        {
            await operation();
            return;
        }

        try
        {
            Suspend = true;
            await _azureExecutionStrategy.ExecuteAsync(operation,cancellationToken);
        }
        finally
        {
            Suspend = false;
        }
    }

    public virtual async Task<TResult> ExecuteAsync<TResult>(Func<Task<TResult>> operation,CancellationToken cancellationToken)
    {
        if (!RetriesOnFailure)
        {
            return await operation();
        }

        try
        {
            Suspend = true;
            return await _azureExecutionStrategy.ExecuteAsync(operation,cancellationToken);
        }
        finally
        {
            Suspend = false;
        }
    }
}

public class MyConfiguration : DbConfiguration
{
    public MyConfiguration()
    {
        SetExecutionStrategy("System.Data.SqlClient",() => new SuspendableSqlAzureExecutionStrategy());
    }
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读