1. 程式人生 > >EF6學習筆記二十六:連接彈性

EF6學習筆記二十六:連接彈性

相同 fck master tel 學習筆記 mage ber 個數 azure

要專業系統地學習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那些東西再寫一下的。不過想到也沒有太了解,也就沒有耐心了。

EF6學習筆記二十六:連接彈性