摘要:試試 Entity Framework v6 新增的「連線彈性」功能。
簡介
Entity Framework v6 在資料庫連線管理方面有一些改進和新增功能,其中一項新功能叫做連線彈性(Connection Resilience),或稱為連線重試。會需要這項功能,是因為資料庫有時會處於短暫無法連接或無法服務的情況,例如網路不穩定或伺服器負載過重導致 SQL Server 突然暫時無法連接,但過了十秒之後就恢復正常。以往碰到這種狀況,開發人員可能得自行實作重試 邏輯。現在 EF 6 內建此功能,提供我們更多彈性來實作資料庫操作失敗時的重試機制。
更新:就在剛發布完這篇,得知 EF 6.1 RTM 了。Ya!
小實驗
我用一個簡單的 Console 程式來做點小實驗,程式碼如下:
執行此程式之前,先把 Northwind 資料庫設定成離線狀態,然後觀察程式執行的結果,如下圖:
從執行結果可以發現,當資料庫連不上的時候,很快就傳回錯誤了,中間不過一秒的時間(即使在連線字串中指定 Connection Timeout 也一樣)。
在加入 EF 6 的失敗自動重試功能之前,先來了解一個相關概念:執行策略。
EF 6 的重試功能
EF 6 的連線重試邏輯是由 IDbExecutionStrategy 介面來定義執行策略的基礎操作,而實作此介面的類別必須負責提供重試機制,亦即當執行的動作失敗時,該類別必須決定是否需要重試。
EF 6 內建四種執行策略:
加入重試邏輯
欲使用執行策略,必須要先設定 EF 的組態。一個比較簡單的方法,就是透過 DbConfiguration 類別的 SetExecutionStrategy 方法。
首先,在你的 DbContext 類別所在的專案中加入一個新類別,類別名稱假設叫做 MyEFConfig。程式碼如下:
在此範例中,MyEFConfig 類別的建構函式呼叫了 SetExecutionStrategy 方法來指定執行策略。這裡使用的執行策略是另一個自訂類別 MySqlAzureExecutionStrategy 的執行個體,而且建立此執行策略物件時,明確指定最多重試 4 次,且最長的重試間隔時間不可超過 15 秒。也就是說,重試達 4 次或者重試間隔時間已經遞增到超過 15 秒時,就不再重試。注意:MyEFConfig 類別必須跟你的 DbContext 類別放在同一個組件裡。
底下是 MySqlAzureExecutionStrategy 類別的程式碼:
OK! 這樣就行了,原本 Main 函式中的程式碼完全不用更動。再執行一次看看,結果如下圖:
從圖中可以看到,這次是花了超過一分鐘才放棄連線,其中經過了四次重試。
看樣子,這機制正好可以用來解決最近碰到的 SQL Server 暫時無法連線的問題。不過,自動重試機制有些限制,使用時必須特別注意,包括:
Happy coding!
簡介
Entity Framework v6 在資料庫連線管理方面有一些改進和新增功能,其中一項新功能叫做連線彈性(Connection Resilience),或稱為連線重試。會需要這項功能,是因為資料庫有時會處於短暫無法連接或無法服務的情況,例如網路不穩定或伺服器負載過重導致 SQL Server 突然暫時無法連接,但過了十秒之後就恢復正常。以往碰到這種狀況,開發人員可能得自行實作重試 邏輯。現在 EF 6 內建此功能,提供我們更多彈性來實作資料庫操作失敗時的重試機制。
更新:就在剛發布完這篇,得知 EF 6.1 RTM 了。Ya!
小實驗
我用一個簡單的 Console 程式來做點小實驗,程式碼如下:
static void Main(string[] args) { var db = new Model.NorthwindEntities(); using (db) { var qry = from t in db.Customers select t; Console.WriteLine("Before connecting: {0:HH:mm:ss}", DateTime.Now); try { var customer = qry.FirstOrDefault(); Console.WriteLine("Done: {0:HH:mm:ss}", DateTime.Now); } catch (Exception ex) { Console.WriteLine("Connection failed: {0:HH:mm:ss}", DateTime.Now); Console.WriteLine("Error: {0}", ex.Message); } } }
執行此程式之前,先把 Northwind 資料庫設定成離線狀態,然後觀察程式執行的結果,如下圖:
從執行結果可以發現,當資料庫連不上的時候,很快就傳回錯誤了,中間不過一秒的時間(即使在連線字串中指定 Connection Timeout 也一樣)。
在加入 EF 6 的失敗自動重試功能之前,先來了解一個相關概念:執行策略。
EF 6 的重試功能
EF 6 的連線重試邏輯是由 IDbExecutionStrategy 介面來定義執行策略的基礎操作,而實作此介面的類別必須負責提供重試機制,亦即當執行的動作失敗時,該類別必須決定是否需要重試。
EF 6 內建四種執行策略:
- DefaultExecutionStrategy:完全不重試任何失敗的操作。這是非 SQL Server 資料庫的預設執行策略。
- DefaultSqlExecutionStrategy:預設的執行策略。它不會重試失敗的操作,但會把可能屬於短暫失效的狀況包在 exception 物件裡面,讓使用者注意到可能需要使用重試機制。
- DbExecutionStrategy:此類別實作了「指數型遞增重試策略」,當操作失敗時,第一次的重試會在間隔 0 秒之後重試(亦即立刻重試);此後的重試間隔時間會以指數的幅度遞增(例如 1 秒、2 秒、4 秒....),直到重試次數已達最高次數限制。此類別有個抽象方法 ShouldRetryOn,讓子類別可以在此方法中根據當時的錯誤狀況來決定要不要重試。
- SqlAzureExecutionStrategy:繼承自 DbExecutionStrategy,會針對 SqlAzure 的一些已知的暫時失效狀況進行重試。
加入重試邏輯
欲使用執行策略,必須要先設定 EF 的組態。一個比較簡單的方法,就是透過 DbConfiguration 類別的 SetExecutionStrategy 方法。
首先,在你的 DbContext 類別所在的專案中加入一個新類別,類別名稱假設叫做 MyEFConfig。程式碼如下:
public class MyEFConfig : DbConfiguration { public MyEFConfig() { SetExecutionStrategy("System.Data.SqlClient", () => new MySqlAzureExecutionStrategy(4, TimeSpan.FromSeconds(15))); } }
在此範例中,MyEFConfig 類別的建構函式呼叫了 SetExecutionStrategy 方法來指定執行策略。這裡使用的執行策略是另一個自訂類別 MySqlAzureExecutionStrategy 的執行個體,而且建立此執行策略物件時,明確指定最多重試 4 次,且最長的重試間隔時間不可超過 15 秒。也就是說,重試達 4 次或者重試間隔時間已經遞增到超過 15 秒時,就不再重試。注意:MyEFConfig 類別必須跟你的 DbContext 類別放在同一個組件裡。
底下是 MySqlAzureExecutionStrategy 類別的程式碼:
public class MySqlAzureExecutionStrategy : SqlAzureExecutionStrategy { private List<int> _errorCodesToRetry = new List<int> { // 把所有想要重試的錯誤代碼加入此串列. 18456 }; public MySqlAzureExecutionStrategy(int maxRetryCount, TimeSpan maxDelay) : base(maxRetryCount, maxDelay) { } protected override bool ShouldRetryOn(Exception exception) { var sqlException = exception as SqlException; if (sqlException != null) { foreach (SqlError err in sqlException.Errors) { // 如果不知道哪些錯誤狀況需要重試,先用下面這行查看錯誤代碼,然後將它加入 _errorCodesToRetry 串列. // Console.WriteLine("ShouldRetryOn: " + err.Message + " , " + err.Number); if (_errorCodesToRetry.Contains(err.Number)) { return true; } } } return base.ShouldRetryOn(exception); } }
OK! 這樣就行了,原本 Main 函式中的程式碼完全不用更動。再執行一次看看,結果如下圖:
從圖中可以看到,這次是花了超過一分鐘才放棄連線,其中經過了四次重試。
看樣子,這機制正好可以用來解決最近碰到的 SQL Server 暫時無法連線的問題。不過,自動重試機制有些限制,使用時必須特別注意,包括:
- 不支援串流操作;
- 不支援手動交易管理(明確呼叫 DbContext 物件的 Database.BeginTransaction 方法來啟動交易)。
Happy coding!
沒有留言: