zoukankan      html  css  js  c++  java
  • EF/EFCore扩展支持with(nolock)查询

    sqlserver执行sql的时候是带有lock的,这样可能会造成死锁现象

    在使用ef/efcore时,生成的sql都是带有lock的,所以当使用ef组件时,需要单独设置一下with nolock

    1. net fx集成

    我的项目基于net fx4.6.1,ef版本是6.1.3版本

    首先在项目中增加WithNoLockInterceptor

    /// <summary>
        /// ef实现withnolock,给表名后面添加with(nolock),不适用.net core
        /// </summary>
        public class WithNoLockInterceptor : DbCommandInterceptor
        {
            private static readonly Regex TableAliasRegex = new Regex(@"(?<tableAlias>[dbo].[w+] AS [Extentd+](?! WITH(NOLOCK)))", RegexOptions.Multiline | RegexOptions.IgnoreCase);
    
            /// <summary>
            /// https://www.bbsmax.com/A/8Bz8V6V65x/
            /// 建议不要为标记为 ThreadStaticAttribute 的字段指定初始值,因为这样的初始化只会发生一次,因此在类构造函数执行时只会影响一个线程。
            /// 在不指定初始值的情况下,如果它是值类型,可依赖初始化为其默认值的字段,如果它是引用类型,则可依赖初始化为空引用的字段。
            /// </summary>
            [ThreadStatic]
            public static bool Uselocking;
    
            [ThreadStatic]
            public static string CommandText;
    
            public override void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
            {
                if (!Uselocking)
                {
                    command.CommandText = TableAliasRegex.Replace(command.CommandText, "${tableAlias} WITH(NOLOCK) ");
                    CommandText = command.CommandText;
                }
            }
    
            public override void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
            {
                if (!Uselocking)
                {
                    command.CommandText = TableAliasRegex.Replace(command.CommandText, "${tableAlias} WITH(NOLOCK) ");
                    CommandText = command.CommandText;
                }
            }
        }
    

      然后在Global.asax.cs里面添加引用

    DbInterception.Add(new WithNoLockInterceptor());

    这样全局设置,可能有些sql想带lock,所以新建一个扩展类:

    WithNoLockUtility

    public static class WithNoLockUtility
        {
            /// <summary>
            /// 部分查询需要使用锁查询的,可以调用此扩展(默认全局查询使用with(nolock))
            /// 参考:https://github.com/aspnetboilerplate/aspnetboilerplate/issues/1637/
            /// 示例:
            /// 1、query.OrderByCustom(filters.orderFields).Select({...}).UseLocking(querable => querable.PagingAsync(filters.page, filters.rows));
            /// 2、repository.EntitiesAsNoTracking.Select(...).UseLocking(item=>item.FirstOrDefaultAsync());
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <typeparam name="TResult"></typeparam>
            /// <param name="query"></param>
            /// <param name="queryAction"></param>
            /// <returns></returns>
            public static TResult UseLocking<T, TResult>(this IQueryable<T> query, Func<IQueryable<T>, TResult> queryAction)
            {
                WithNoLockInterceptor.Uselocking = true;
    
                TResult queryableResult = default(TResult);
                try
                {
                    queryableResult = queryAction(query);
                }
                finally
                {
                    WithNoLockInterceptor.Uselocking = false;
                }
    
                return queryableResult;
            }
        }
    

      使用方式参考示例,不过这个方法我没有测试使用

    2. netcore集成

    这个直接参考这一篇文章:https://www.cnblogs.com/weihanli/p/12623934.html

    使用拦截器:

    public class QueryWithNoLockDbCommandInterceptor : DbCommandInterceptor
    {
        private static readonly Regex TableAliasRegex =
            new Regex(@"(?<tableAlias>AS [[a-zA-Z]w*](?! WITH (NOLOCK)))",
                RegexOptions.Multiline | RegexOptions.Compiled | RegexOptions.IgnoreCase);
    
        public override InterceptionResult<object> ScalarExecuting(DbCommand command, CommandEventData eventData, InterceptionResult<object> result)
        {
            command.CommandText = TableAliasRegex.Replace(
                command.CommandText,
                "${tableAlias} WITH (NOLOCK)"
                );
            return base.ScalarExecuting(command, eventData, result);
        }
    
        public override Task<InterceptionResult<object>> ScalarExecutingAsync(DbCommand command, CommandEventData eventData, InterceptionResult<object> result,
            CancellationToken cancellationToken = new CancellationToken())
        {
            command.CommandText = TableAliasRegex.Replace(
                command.CommandText,
                "${tableAlias} WITH (NOLOCK)"
                );
            return base.ScalarExecutingAsync(command, eventData, result, cancellationToken);
        }
    
        public override InterceptionResult<DbDataReader> ReaderExecuting(DbCommand command, CommandEventData eventData, InterceptionResult<DbDataReader> result)
        {
            command.CommandText = TableAliasRegex.Replace(
                command.CommandText,
                "${tableAlias} WITH (NOLOCK)"
                );
            return result;
        }
    
        public override Task<InterceptionResult<DbDataReader>> ReaderExecutingAsync(DbCommand command, CommandEventData eventData, InterceptionResult<DbDataReader> result,
            CancellationToken cancellationToken = new CancellationToken())
        {
            command.CommandText = TableAliasRegex.Replace(
                command.CommandText,
                "${tableAlias} WITH (NOLOCK)"
                );
            return base.ReaderExecutingAsync(command, eventData, result, cancellationToken);
        }
    }
    

      然后在configservice里面添加

    var services = new ServiceCollection();
    services.AddDbContext<TestDbContext>(options =>
    {
        options
            .UseLoggerFactory(loggerFactory)
            .UseSqlServer(DbConnectionString)
            .AddInterceptors(new QueryWithNoLockDbCommandInterceptor())
            ;
    });
    

      这样就可以全局开启with nolock了

    以上均是参考网上资料写的,mark一下防止丢失

    参考:

    1.https://www.cnblogs.com/weihanli/p/12623934.html

    2.https://www.cnblogs.com/slyzly/articles/11452341.html

  • 相关阅读:
    Odoo Entypo Regular Icon List
    Ubuntu 循环遍历当前目录下所有文本文件中的字符
    FairyGUI学习
    FairyGUI和NGUI对比
    热更新有多重要?游戏代码热更新杂谈
    收藏的链接
    Vuforia AR实战教程
    BleedTree动画混合树
    Unity3d导出安卓版本
    Unity+高通Vuforia SDK——AR
  • 原文地址:https://www.cnblogs.com/walt/p/14765665.html
Copyright © 2011-2022 走看看