• EF6学习笔记二十六:连接弹性


    要专业系统地学习EF推荐《你必须掌握的Entity Framework 6.x与Core 2.0》。这本书作者(汪鹏,Jeffcky)的博客:https://www.cnblogs.com/CreateMyself/

    连接弹性这一节,作者说的不是很多,而且又出现一个polly库,感觉弄下去真的要花不少时间。

    这一块我目前没有准备继续去弄,也就简单记录一下我从这一节内容中学到的东西吧。

    连接弹性,什么意思呢?就是你数据库的连接要是断开了,那么还有其他的机制还对这一情况做处理。如果说连接一断就随他去了,显然不够有“弹性”。

    说到这一点我想到了我在学习node.js时用到的一个启动器,叫forever,当然启动器也有很多种。什么意思呢?如果说你的服务跑起来了,不用启动器的情况,一个小的错误就能造成你服务关闭。那么我用启动器来启动我的项目就不会出来这种情况。

    一般很多部署node程序会用到pm2,这个也差不多就是这种功能,它有一个守护进程,让你的网站不至于一个错误就停止了。

    所以我就弄不懂IIS中怎么就没听说过有什么启动器。node里面学的东西其实没多少,就是使用各种包,也不用去管具体实现。有点没劲。最有用的就是它和.net程序之间的差异能够让人引发很多思考。

    说回EF中连接弹性的问题。其实如果说数据库连接断开了,可能会有很多种情况,可能因为是网络问题啊。那么我们能够想到的应对方法就是去重试。

    EF提供了大量有关暂时异常的信息。如果由于任何原因与数据源的连接丢失并且未达到重试限制,那么它将会以和禁用连接弹性相同的方式引发异常。

    EF6.X上给与了一下4种连接策略

    1.DefaultExceptionStrategy:默认执行策略,当失败时,对除SQL Server 以外的数据库不会进行重试。

    2.DefaultSqlExecutionStrategy:根本不会重试,但是会包含任何可能的短暂异常,以通知开发者可能需要启用连接弹性,次类受保护限制。

    3.DbExecutionStrategy:此类适用于其他执行策略的基类,以指数实现重试策略,其中初始重试以0计数,并且延迟指数增加,知道命中最大重试计数。次类具有抽象的ShouldRetryOn方法,可以在派生执行策略中实现,以控制应重试哪些异常。

    4.SqlAzureExecutionStrategy:该执行策略继承自DbExecutionStrategy,并将重试在使用SqlAzure时可能一直出现的异常。

    上面的是书中的原话,我还是得用自己的话说一下,数据源连接丢失,EF默认是有重试的。但是我按照书上的代码写出来,有一些疑问。

    来看一下写一个派生自DbExecutionStrategy,首先我了解到,数据库连接丢失,EF会调用哪个方法,那就知道了有这个切入点吧.

    ShouldRetryOn方法中我只是加了一句console,还是执行的基类的代码

     public class SqlServerExecutionStrategy : DbExecutionStrategy
        {
            public SqlServerExecutionStrategy()
            {
    
            }
    
            /// <summary>
            /// 确定指定的异常是否表示临时故障   如果指定的异常被认为是暂时的,则为true,否则为false。
            /// </summary>
            /// <param name="maxRetryCount">最大重试次数</param>
            /// <param name="maxDelay">最大等待时长</param>
            public SqlServerExecutionStrategy(int maxRetryCount, TimeSpan maxDelay) : base(maxRetryCount, maxDelay)
            {
                
            }
    
            protected override bool ShouldRetryOn(Exception exception)
            {
                //  同样的是打印四次
                Console.WriteLine("777777777777777777777777777");
                throw new NotImplementedException();
            }
    }
    View Code

    写一个派生自DbConfiguration的类,在EF中注册配置。

    public class EFConfiguration : DbConfiguration
        {
            public EFConfiguration()
            {
                SetExecutionStrategy(SqlProviderServices.ProviderInvariantName, () => new SqlServerExecutionStrategy(3, TimeSpan.FromSeconds(5)));
            }
        }
    View Code

    然后我关闭sqlserver服务,这样它将连接不到数据库

    可以看到打印了4次,那意思是重试连接了4次吗?

     在EFConfiguration传递的3和5,意思是重试次数为3次,最大延迟时间为5秒,那么我改成重试1次,还是一样,这个方法被调用4次。所以我就怀疑这是不是有问题?

    如果开启sqlserver服务,这个方法一次都不会被调用

    途中我碰到一个问题,就是我的sqlsever服务断开之后,运行程序,控制台过了很久才出现内容,为什么等待了那么久?我突然想到连接字符串里面有个Connect Timeout属性,默认是30秒.于是我改成5秒,发现确实是这里的问题。

     

    接着来看作者在shouldRetryOn方法中写的代码,我加了三句console

     protected override bool ShouldRetryOn(Exception exception)
            {
                Console.WriteLine("11111111111111111111111111111111111111111");
                bool bRetry = false;
                if (exception is SqlException objSqlException)
                {
                    Console.WriteLine("222222222222222222222222222222222");
                    var lstErrorNumbersToRetry = new List<int>() { 5 };
                    if (objSqlException.Errors.Cast<SqlError>().Any(a => lstErrorNumbersToRetry.Contains(a.Number)))
                    {
                        Console.WriteLine("33333333333333333333333333333");
                        bRetry = true;
                    }
                }
                return bRetry;
            }
    View Code

    同样关闭Sqlserver服务来执行看一下

    shouldRetryOn这个方法返回的是bool类型,如果异常是短暂的返回true,否则false,刚刚的打印内容可以看到这个异常被认为不是暂时的。

    作者的判断依据是"5"这个数字,但是5代表的是什么呢?

    转到Number定义看一下

     通过这几句注释完全看不到什么有价值的东西。

    幸好.net开源了,那就去MSDN上看一下:https://docs.microsoft.com/zh-cn/dotnet/api/system.data.sqlclient.sqlerror.number?view=netframework-4.7.2#System_Data_SqlClient_SqlError_Number

    它说SqlError.Number类型的值对应master.dbo.sysmessages表,那就去查表吧

     

     但是根本就没有5啊,最小都是21,。我其实也把异常里面的Number看了一下,发现是2

    protected override bool ShouldRetryOn(Exception exception)
            {
                Console.WriteLine("11111111111111111111111111111111111111111");
                bool bRetry = false;
                if (exception is SqlException objSqlException)
                {
                    Console.WriteLine("222222222222222222222222222222222");
                    var lstErrorNumbersToRetry = new List<int>() { 5 };
                    var abc = objSqlException.Errors.Cast<SqlError>();
                    var str = "";
                    foreach (var item in abc)
                    {
                        str += item.Number + ",";
                    }
                    var str2 = str;  //  2,
                    if (objSqlException.Errors.Cast<SqlError>().Any(a => lstErrorNumbersToRetry.Contains(a.Number)))
                    {
                        Console.WriteLine("33333333333333333333333333333");
                        bRetry = true;
                    }
                }
                return bRetry;
            }
    View Code

    行,到此为止,这个对我来说已经进行不下去了。

    总结一下我通过写一个派生自DbExecutionStrategy类有什么作用呢?作用就是知道数据库连接丢失,shouldRetryOn方法会被调用,这一点是肯定的,那么其他的东西不怎么明白也就不妄下结论了

    这就是简单的连接弹性。现在来说道Polly库。

    这个是做什么的呢?其实我觉得就是对异常处理做出的一种规范。

    数据库连接断开,只有重试吧?原因有很多种,很有可能他就一直断开了。所以Polly他为你是解决不了的。你说你自己都不知道发生什么问题,polly又能怎么办。

    我刚开始就是认为,用这个那一定是不管什么情况下的连接丢失,polly都能帮我解决,这就不对了。

    我觉得Polly就是提供了对异常处理的规范,它有很多种策略,可以参考Jeffcky的一篇博客:https://www.cnblogs.com/CreateMyself/p/7589397.html

    行吧,就这了。我开始想把polly那些东西再写一下的。不过想到也没有太了解,也就没有耐心了。

  • 相关阅读:
    跨期套利策略
    读书笔记 量化交易:如何建立自己的算法交易事业
    ESP8266固件修改可以控制多个IO方法
    ESP8266固件烧录方法
    关于毕设WiFi选型
    关于(x&y)+((x^y)>>1)的探究
    QML添加右键菜单
    初学QML之QML和C++混合方法
    初学QML之qmlRegisterType
    我的第一个QML Button的实现
  • 原文地址:https://www.cnblogs.com/jinshan-go/p/10349493.html
Copyright © 2020-2023  润新知