zoukankan      html  css  js  c++  java
  • 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那些东西再写一下的。不过想到也没有太了解,也就没有耐心了。

  • 相关阅读:
    ‘Host’ is not allowed to connect to this mysql server
    centos7安装mysql
    further configuration avilable 不见了
    Dynamic Web Module 3.0 requires Java 1.6 or newer
    hadoop启动 datanode的live node为0
    ssh远程访问失败 Centos7
    Linux 下的各种环境安装
    Centos7 安装 python2.7
    安装scala
    Centos7 安装 jdk 1.8
  • 原文地址:https://www.cnblogs.com/jinshan-go/p/10349493.html
Copyright © 2011-2022 走看看