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(); } }
写一个派生自DbConfiguration的类,在EF中注册配置。
public class EFConfiguration : DbConfiguration { public EFConfiguration() { SetExecutionStrategy(SqlProviderServices.ProviderInvariantName, () => new SqlServerExecutionStrategy(3, TimeSpan.FromSeconds(5))); } }
然后我关闭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; }
同样关闭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; }
行,到此为止,这个对我来说已经进行不下去了。
总结一下我通过写一个派生自DbExecutionStrategy类有什么作用呢?作用就是知道数据库连接丢失,shouldRetryOn方法会被调用,这一点是肯定的,那么其他的东西不怎么明白也就不妄下结论了
这就是简单的连接弹性。现在来说道Polly库。
这个是做什么的呢?其实我觉得就是对异常处理做出的一种规范。
数据库连接断开,只有重试吧?原因有很多种,很有可能他就一直断开了。所以Polly他为你是解决不了的。你说你自己都不知道发生什么问题,polly又能怎么办。
我刚开始就是认为,用这个那一定是不管什么情况下的连接丢失,polly都能帮我解决,这就不对了。
我觉得Polly就是提供了对异常处理的规范,它有很多种策略,可以参考Jeffcky的一篇博客:https://www.cnblogs.com/CreateMyself/p/7589397.html
行吧,就这了。我开始想把polly那些东西再写一下的。不过想到也没有太了解,也就没有耐心了。