Share via


處理暫時性錯誤並有效地連線到適用於 MySQL 的 Azure 資料庫

適用於: 適用於 MySQL 的 Azure 資料庫 - 單一伺服器

重要

「適用於 MySQL 的 Azure 資料庫」單一伺服器位於淘汰路徑上。 強烈建議您升級至適用於 MySQL 的 Azure 資料庫彈性伺服器。 如需移轉至「適用於 MySQL 的 Azure 資料庫」彈性伺服器的詳細資訊,請參閱「適用於 MySQL 的 Azure 資料庫」單一伺服器會發生什麼事?

本文說明如何處理暫時性錯誤,並且有效率地連線到適用於 MySQL 的 Azure 資料庫。

暫時性錯誤

暫時性錯誤 (也稱為暫時性故障) 係指會自行解決的錯誤。 這些錯誤最常顯現在與正在卸除之資料庫伺服器的連線。 此外,與伺服器的新連線也無法開啟。 舉例來說,當發生硬體或網路故障時,就可能發生暫時性錯誤。 另一個原因可能是正在推出新的 PaaS 服務版本。這些事件大多數都會由系統在 60 秒內自動解決。 設計及開發雲端應用程式時,最佳做法是將暫時性錯誤納入考量。 假設這些錯誤可能隨時在任何元件發生,並備妥適當的邏輯來處理這些情況。

處理暫時性錯誤

您應該使用重試邏輯來處理暫時性錯誤。 必須考量的情況:

  • 您嘗試開啟連線時發生錯誤
  • 伺服器端卸除閒置的連線。 當您嘗試發出命令時卻無法執行該命令
  • 目前正在執行命令的作用中連線被卸除。

第一種和第二種情況的處理方式相當直接。 請嘗試重新開啟連線。 成功時,即表示系統已解決暫時性錯誤。 您可以再次使用「適用於 MySQL 的 Azure 資料庫」。 建議您先稍候,再重試連線。 如果初始重試失敗,請先放棄。 如此一來,系統才能使用所有可用資源來解決錯誤情況。 建議採用的模式為:

  • 先等候 5 秒,再進行第一次重試。
  • 針對接下來的每次重試,依指數遞增等候時間,最多可達 60 秒。
  • 設定應用程式將作業視為失敗的重試次數上限。

當具有作用中交易的連線失敗時,比較難正確地處理復原。 有兩種情況:如果交易本質上是唯讀的,您可以放心地重新開啟連線並重試交易。 不過,如果交易也對資料庫進行寫入,則必須判斷該交易是否已回復,或是在發生暫時性錯誤前即已成功。 在該情況下,您可能只是尚未收到來自資料庫伺服器的認可通知。

其中一種做法是,在用戶端上產生一個用於所有重試的唯一識別碼。 您需將這個唯一識別碼隨著交易一起傳遞給伺服器,並將它與一個唯一條件約束一起儲存在資料行中。 如此一來,您便可以放心地重試交易。 如果先前的交易已復原,且用戶端產生的唯一識別碼尚未存在於系統中,交易即會成功。 如果因先前的交易已順利完成而使得先前已儲存唯一識別碼,交易便會因發生重複索引鍵違規而失敗。

當您的程式透過第三方中介軟體與「適用於 MySQL 的 Azure 資料庫」進行通訊時,請詢問廠商中介軟體是否包含暫時性錯誤的重試邏輯。

請務必測試您的重試邏輯。 例如,擴大或縮小「適用於 MySQL 的 Azure 資料庫」伺服器的計算資源時,請嘗試執行您的程式碼。 您的應用程式應該要能夠毫無問題地處理在此作業期間發生的短暫停機情況。

有效率地連線到適用於 MySQL 的 Azure 資料庫

資料庫連線為有限的資源,因此有效利用連線共用來存取適用於 MySQL 的 Azure 資料庫,將效能最佳化。 以下章節說明如何使用連線共用或持續連線,以更有效率地存取適用於 MySQL 的 Azure 資料庫。

管理資料庫連線,可能會對應用程式整體的效能產生重大影響。 若要最佳化應用程式的效能,目標應該是減少建立連線的次數,以及在索引鍵程式碼路徑中建立連線的時間。 強烈建議您使用資料庫連線共用或持續連線,藉以連線至適用於 MySQL 的 Azure 資料庫。 資料庫連線共用會處理資料庫連線的建立、管理和配置。 當程式要求資料庫連線時,則會優先配置現有的閒置資料庫連線,而非建立新的連線。 該程式完成使用資料庫連線之後,會復原連線以準備進一步使用,而不只是關閉。

為進一步說明,本文提供使用 JAVA 作為範例的程式碼片段。 如需詳細資訊,請參閱 Apache 一般 DBCP

注意

該伺服器會設定逾時機制,關閉處於閒置狀態一段時間的連線,以利於釋放資源。 請務必設定驗證系統,以確保使用持續連線時的有效性。 如需詳細資訊,請參閱在用戶端設定驗證系統,以確保持續連線的有效性

持續連線的概念類似於連線共用的概念。 將短暫連線取代為持續連線,只需要對程式碼進行小變更,但是在許多一般應用程式案例中,改善效能方面會有重大影響。

使用等候和重試機制搭配短暫連線來存取資料庫

如果您有資源限制,強烈建議您使用資料庫共用或持續連線來存取資料庫。 如果您的應用程式在接近並行連線數目的上限時,使用短暫連線並遇到連線失敗,您可以嘗試等候和重試機制。 您可以設定適當的等候時間,讓第一次嘗試之後的等候時間縮短。 之後,您可以嘗試多次等候事件。

在用戶端中設定驗證機制,以確認持續連線的有效性

伺服器會設定逾時機制,關閉處於閒置狀態一段時間的連線,以利於釋放資源。 當用戶端再次存取資料庫時,相當於在用戶端與伺服器之間要求建立新的連線。 如果要確保連線在使用這些連線程序期間的有效性,請在用戶端上設定驗證機制。 如下列範例所示,您可以使用 Tomcat JDBC 連線共用來設定此驗證機制。

透過設定 TestOnBorrow 參數,當有新的要求時,連線共用會自動驗證任何可用閒置連線的有效性。 如果這類連線有效,則會直接傳回,否則連線共用會撤銷連線。 然後,連線共用會建立新的有效連線並將其傳回。 此流程可確保能有效率地存取資料庫。

如需特定設定的詳細資訊,請參閱 JDBC 連線共用官方簡介文件。 您主要需要設定下列三個參數:TestOnBorrow (設定為 true)、ValidationQuery (設定為 SELECT 1) 和 ValidationQueryTimeout (設定為 1)。 特定範例程式碼如下所示:

public class SimpleTestOnBorrowExample {
      public static void main(String[] args) throws Exception {
          PoolProperties p = new PoolProperties();
          p.setUrl("jdbc:mysql://localhost:3306/mysql");
          p.setDriverClassName("com.mysql.jdbc.Driver");
          p.setUsername("root");
          p.setPassword("password");
            // The indication of whether objects will be validated by the idle object evictor (if any). 
            // If an object fails to validate, it will be dropped from the pool. 
            // NOTE - for a true value to have any effect, the validationQuery or validatorClassName parameter must be set to a non-null string. 
          p.setTestOnBorrow(true); 

            // The SQL query that will be used to validate connections from this pool before returning them to the caller.
            // If specified, this query does not have to return any data, it just can't throw a SQLException.
          p.setValidationQuery("SELECT 1");

            // The timeout in seconds before a connection validation queries fail. 
            // This works by calling java.sql.Statement.setQueryTimeout(seconds) on the statement that executes the validationQuery. 
            // The pool itself doesn't timeout the query, it is still up to the JDBC driver to enforce query timeouts. 
            // A value less than or equal to zero will disable this feature.
          p.setValidationQueryTimeout(1);
            // set other useful pool properties.
          DataSource datasource = new DataSource();
          datasource.setPoolProperties(p);

          Connection con = null;
          try {
            con = datasource.getConnection();
            // execute your query here
          } finally {
            if (con!=null) try {con.close();}catch (Exception ignore) {}
          }
      }
  }

下一步