PolarDB-X JDBC ドライバ (polardbx-connector-java)

> 本記事は[こちらのブログ](https://www.alibabacloud.com/blog/polardb-x-jdbc-driver-polardbx-connector-java_602231?spm=a2c65.11461433.0.0.4ee35355xnGg8q)を参考にしています。
> 翻訳にはアリババクラウドの[ModelStudio](https://www.alibabacloud.com/en/product/modelstudio)([Qwen](https://www.alibabacloud.com/en/solutions/generative-ai/qwen))を使用しております。

# PolarDB-X 2.0 をより簡単に使用するための JDBC ドライバ

<a href=https://www.alibabacloud.com/product/polardb-for-xscale target=_blank>PolarDB-X</a> 2.0 をより簡単に使用するために、PolarDB-X は Java 向けの標準的な JDBC ドライバを提供しています。このドライバを使用することで以下を実現できます：

- PolarDB-X 2.0 Standard Edition に直接接続し、HA（高可用性）後に新しいプライマリノードへの自動接続を提供します。
- PolarDB-X 2.0 Standard Edition に直接接続し、定期的な3ノード切り替え時のスムーズなフェイルオーバーを提供します。
- PolarDB-X 2.0 Enterprise Edition に直接接続し、複数ノード間での負荷分散を実現します。

## 基本情報

### Maven 依存関係
このドライバは `polardbx-connector-java` であり、`mysql-connector-java` を `provided` モードで依存しています。これにより、ユーザーは使用する MySQL JDBC コネクタを選択できます。xml
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.33</version>
</dependency>

<dependency>
    <groupId>com.alibaba.polardbx</groupId>
    <artifactId>polardbx-connector-java</artifactId>
    <version>2.1.2</version>
</dependency>

## 使用上の注意

### サンプル JDBC URL:text
jdbc:polardbx://11.167.60.147:6991/test

### ドライバパッケージ名:text
com.alibaba.polardbx.Driver

### プロトコルヘッダ:text
polardbx

### 指定された IP とポート:

#### Standard Edition
- IP:port、または VIP:port、または IP0:port0,IP1:port1（ノードは同じクラスター内にあり、英語のカンマ（`,`）で区切る必要があります）。接続時にリーダーノードにルーティングされます。

#### Enterprise Edition
- IP:port、または VIP:port、または IP0:port0,IP1:port1（ノードは同じクラスター内にあり、英語のカンマ（`,`）で区切る必要があります）。接続時にクラスタ内のランダムな読み書きノードに負荷分散されます。

### 追加パラメータ:
- **clusterId**: クラスターの ID。誤接続を避けるために検証に使用します。指定しない場合、最初の接続時に取得されます。
- **haCheckConnectTimeoutMillis**: HA 検出の接続タイムアウト時間（デフォルト：3000ミリ秒）。
- **haCheckSocketTimeoutMillis**: HA 検出のクエリタイムアウト時間（デフォルト：3000ミリ秒）。
- **haCheckIntervalMillis**: HA 検出の間隔（デフォルト：1000ミリ秒）。
- **checkLeaderTransferringIntervalMillis**: スムーズなフェイルオーバー検出の間隔（デフォルト：100ミリ秒）。
- **leaderTransferringWaitTimeoutMillis**: スムーズなフェイルオーバーの最大ブロッキング待機時間（デフォルト：5000ミリ秒）。
- **smoothSwitchover**: 接続プールがスムーズな高可用性フェイルオーバーをサポートするかどうかを示します。フェイルオーバー中に `isClosed` が呼び出された際に `true` を返すことで、古い接続を接続プールが破棄します（デフォルト値：`true`）。

### 追加動作:
- リーダーを初めて取得するか、HA 切り替えを行う際には、`connectTimeout` パラメータが 5000 ミリ秒に設定されます。それ以外の場合、デフォルトではタイムアウトはありません。

### その他の機能:
- JDK 8 の標準で記述され、以前のバージョンとも互換性があります。
- 標準の JDBC コネクタを参照して、さまざまな接続プールに対応します。
- HA 発生後、既存の接続上のすべてのリクエストはエラーを返します。
- 接続を取得する際、HA 切り替えステータスをチェックすることでスムーズなフェイルオーバーを実現します。
- JDBC URL は MySQL JDBC コネクタと互換性があり、`user`, `password`, `useSSL`, `characterEncoding`, `connectTimeout`, `socketTimeout`, `allowLoadLocalInfile`, `allowPublicKeyRetrieval`, `sslMode`, `characterEncoding`, `useCursorFetch`, `rewriteBatchedStatements`, `netTimeoutForStreamingResults`, `useServerPrepStmts`, `useUnicode` などの共通パラメータをサポートします。

## スムーズなフェイルオーバー機能

<a href=https://www.alibabacloud.com/product/polardb-for-xscale target=_blank>PolarDB-X</a> は、`polardbx-connector-java` ドライバと組み合わせることで、データベースに対してスムーズなフェイルオーバー機能を提供します。例えば、DBA がデータベースのアクティブホストがオフラインになった際の運用保守 (O&M) を行う場合、データベースは HA フェイルオーバーを実行することが期待されます。PolarDB-X データベースとドライバのスムーズなフェイルオーバー機能に基づいて、ビジネス SQL 文の中断やエラー報告なしにシームレスな体験を提供できるため、データベースの使用体験が大幅に向上します。

以下はスムーズなフェイルオーバーの動作原理を示した図です：
![1](https://yqintl.alicdn.com/1c27eead75fccc6087ac7c22d1d86cc2cab2ad24.jpeg)

PolarDB-X が提供するスムーズなフェイルオーバー機能により、ドライバは PolarDB-X Standard Edition の3ノードクラスターの状態をリアルタイムで感知できます。データベースの HA フェイルオーバーが完了する前には次のようになります：

- クライアントドライバは、割り当てられた接続が返されるのをブロックし、フェイルオーバーが完了するまで待ちます。
- サービスが接続を取得した後、リクエストを可能な限り早く完了させ、再利用不可としてマークします。

以下の点に注意してください：

- クライアントドライバは、スムーズなフェイルオーバーのために2つのチェックポイント（接続取得と接続返却）を追加します。
- PolarDB-X Standard Edition の3ノードクラスターの状態をリアルタイムで感知することで、HA フェイルオーバー後の動的な接続再構築機能が実装されます。これは新しい接続を取得する時間を増加させるだけですが、既存の接続でエラーを引き起こしません。そのため、アプリケーションはスケジュールされた切り替えを感知しません。
- サービスがデータベース接続を取得する際には、標準の try-with-resources ステートメントで実装されたデータベース操作を使用することをお勧めします。try ブロック内のサービス実行時間が対応する PolarDB-X によって設定された HA ウィンドウ（`consensus_wait_millisecond_before_change_leader` 時間閾値、デフォルトは1秒）よりも短い場合、スケジュールされた切り替えによるエラーは返されません。
- ただし、長時間実行されるトランザクションが接続を保持し、時間閾値を超えた場合は、それが切り替えプロセスをまたぐため、フェイルオーバー後に書き込みが許可されていないという理由でエラーが報告されます。

現在、PolarDB-X のスムーズなフェイルオーバー機能において推奨される接続プールは、Druid v1.2.24 以降です。xml
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.24</version>
</
<!-- 入力テキストの全てを正確かつ忠実に日本語へ翻訳します。 -->

<property name=testOnBorrow value=false /&gt;
&lt;!-- コネクションがシステムによって返される前に、その状態をチェックするかどうかを指定します。 --&gt;
<property name=testOnReturn value=false /&gt;
&lt;!-- 各コネクションの有効期限を指定します。有効期限が切れたコネクションはシステムによって自動的に閉じられます。このパラメータを指定することで、バックエンドノードの負荷をバランスさせることができます。 --&gt;
<property name=phyTimeoutMillis value=600000 /&gt;
&lt;!-- 各コネクション上で送信できる最大SQLクエリリクエスト数を指定します。あるコネクション上で送信されたSQLクエリリクエスト数がこのパラメータの値に達すると、システムはそのコネクションを閉じます。このパラメータを指定して、バックエンドノードの負荷をバランスさせることができます。 --&gt;
<property name=phyMaxUseCount value=10000 /&gt;
&lt;/bean&gt;

## クイックスタートの例

### 1. ドライバを直接使用してPolarDB-Xに接続java
Class.forName(com.alibaba.polardbx.Driver);

try (final Connection conn = DriverManager.getConnection(
    jdbc:polardbx://127.0.0.1:3306/, root, *****);
    final Statement stmt = conn.createStatement()) {

    try (final ResultSet rs = stmt.executeQuery(select 1)) {
        for (int i = 0; i &lt; rs.getMetaData().getColumnCount(); ++i) {
            System.out.print(rs.getMetaData().getColumnName(i + 1) + \t);
        }
        System.out.println();
        while (rs.next()) {
            for (int i = 0; i &lt; rs.getMetaData().getColumnCount(); ++i) {
                System.out.print(rs.getObject(i + 1) + \t);
            }
            System.out.println();
        }
    }
}

### 2. Druidコネクションプールを使用java
try (final DruidDataSource dataSource = new DruidDataSource()) {
    dataSource.setUrl(jdbc:polardbx://127.0.0.1:3306/);
    dataSource.setUsername(root);
    dataSource.setPassword(*****);
    
    // Druidコネクションプールのバージョンが1.2.23以前の場合、setDriverClassNameとsetExceptionSorterを呼び出してPolarDB-Xドライバに対応させる必要があります。新しいバージョン（1.2.24以降）では、ドライバを自動的に識別できます。
    dataSource.setDriverClassName(com.alibaba.polardbx.Driver);
    dataSource.setExceptionSorter(new MySqlExceptionSorter());

    try (final Connection conn = dataSource.getConnection();
        final Statement stmt = conn.createStatement()) {

        try (final ResultSet rs = stmt.executeQuery(select 1)) {
            for (int i = 0; i &lt; rs.getMetaData().getColumnCount(); ++i) {
                System.out.print(rs.getMetaData().getColumnName(i + 1) + \t);
            }
            System.out.println();
            while (rs.next()) {
                for (int i = 0; i &lt; rs.getMetaData().getColumnCount(); ++i) {
                    System.out.print(rs.getObject(i + 1) + \t);
                }
                System.out.println();
            }
        }
    }
}
あるいは、XMLでデータソースを設定した後、新しいドライバに対応させるために次の2つの項目を追加します：java
dataSource.setDriverClassName(com.alibaba.polardbx.Driver);
dataSource.setExceptionSorter(new MySqlExceptionSorter());

### 3. HikariCPコネクションプールを使用java
Class.forName(com.alibaba.polardbx.Driver);

final HikariConfig config = new HikariConfig();
config.setJdbcUrl(jdbc:polardbx://127.0.0.1:3306/);
config.setUsername(root);
config.setPassword(*****);
config.setMaximumPoolSize(10);

try (HikariDataSource dataSource = new HikariDataSource(config)) {
    try (final Connection conn = dataSource.getConnection();
        final Statement stmt = conn.createStatement()) {

        try (final ResultSet rs = stmt.executeQuery(select 1)) {
            for (int i = 0; i &lt; rs.getMetaData().getColumnCount(); ++i) {
                System.out.print(rs.getMetaData().getColumnName(i + 1) + \t);
            }
            System.out.println();
            while (rs.next()) {
                for (int i = 0; i &lt; rs.getMetaData().getColumnCount(); ++i) {
                    System.out.print(rs.getObject(i + 1) + \t);
                }
                System.out.println();
            }
        }
    }
}

### 4. DBCPコネクションプールを使用java
Class.forName(com.alibaba.polardbx.Driver);

final BasicDataSource dataSource = new BasicDataSource();
dataSource.setUrl(jdbc:polardbx://127.0.0.1:3306/);
dataSource.setUsername(root);
dataSource.setPassword(*****);
dataSource.setInitialSize(5);

try (final Connection conn = dataSource.getConnection();
    final Statement stmt = conn.createStatement()) {

    try (final ResultSet rs = stmt.executeQuery(select 1)) {
        for (int i = 0; i &lt; rs.getMetaData().getColumnCount(); ++i) {
            System.out.print(rs.getMetaData().getColumnName(i + 1) + \t);
        }
        System.out.println();
        while (rs.next()) {
            for (int i = 0; i &lt; rs.getMetaData().getColumnCount(); ++i) {
                System.out.print(rs.getObject(i + 1) + \t);
            }
            System.out.println();
        }
    }
}

## 実際のデモ

テストおよび開発環境でJDK環境を構成します。<a href=https://repo.maven.apache.org/maven2/com/alibaba/polardbx/polardbx-connector-java/2.1.2/polardbx-connector-java-2.1.3.jar target=_blank>polardbx-connector-java-2.1.2.jar</a> と <a href=https://repo.maven.apache.org/maven2/com/mysql/mysql-connector-j/8.0.33/mysql-connector-j-8.0.33.jar target=_blank>mysql-connector-j-8.0.33.jar</a> をダウンロードします。テストファイルを作成し、クラスタのアドレス、ユーザー名、パスワードを置き換えます。ネットワークが接続できることを確認してください。以下のコードは、PolarDB-X Standard Editionクラスタに接続し、クラスタ情報を表示する方法を示しています。java
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class TestDriver {
    public static void main(String[] args) throws Exception {
        Class.forName(com.alibaba.polardbx.Driver);

        try (final Connection conn = DriverManager.getConnection(
            jdbc:polardbx://127.0.0.1:3306/, root, ****);
            final Statement stmt = conn.createStatement()) {

            try (final ResultSet rs = stmt.executeQuery(select * from information_schema.alisql_cluster_global)) {
                for (int i = 0; i &lt; rs.getMetaData().getColumnCount(); ++i) {
                    System.out.print(rs.getMetaData().getColumnName(i + 1) + \t);
                }
                System.out.println();
                while (rs.next()) {
                    for (int i = 0; i &lt; rs.getMetaData().getColumnCount(); ++i) {
                        System.out.print(rs.getObject(i + 1) + \t);
                    }
                    System.out.println();
                }
            }
        }
    }
}

コードをコンパイルして実行します。bash
$javac TestDriver.java

$ll
total 2812
-rw-r--r-- 1 chenyu.zzy users 2481560 Dec  3 17:26 mysql-connector-j-8.0.33.jar
-rw-r--r-- 1 chenyu.zzy users  384133 Dec  3 17:19 polardbx-connector-java-2.1.2.jar
-rw-r--r-- 1 chenyu.zzy users    2442 Dec  3 17:29 TestDriver.class
-rw-r--r-- 1 chenyu.zzy users    1102 Dec  3 17:29 TestDriver.java

# 初回実行時、高可用性機能が取得したクラスタ情報をログインターフェースに出力します。
$java -cp .
:mysql-connector-j-8.0.33.jar:polardbx-connector-java-2.1.2.jar TestDriver  
2024年12月3日 午後5時29分58秒 com.alibaba.polardbx.HaManager info  
INFO: バックエンドクラスタの状態が次のように変更されました: [{tag:127.0.0.1:6991,host:127.0.0.1,port:6991,xport:34991,paxos_port:14991,role:Leader,peers:[{tag:11.167.60.147:6992,host:11.167.60.147,port:6992,xport:-1,paxos_port:14992,role:Follower,version:8.0.32-X-Cluster-8.4.20-20241014,cluster_id:6990,update_time:2024-12-03 17:29:58 GMT+08:00},{tag:11.167.60.147:6993,host:11.167.60.147,port:6993,xport:-1,paxos_port:14993,role:Follower,version:8.0.32-X-Cluster-8.4.20-20241014,cluster_id:6990,update_time:2024-12-03 17:29:58 GMT+08:00},{tag:127.0.0.1:6991,host:11.167.60.147,port:6991,xport:34991,paxos_port:14991,role:Leader,version:8.0.32-X-Cluster-8.4.20-20241014,cluster_id:6990,update_time:2024-12-03 17:29:58 GMT+08:00}],version:8.0.32-X-Cluster-8.4.20-20241014,cluster_id:6990,update_time:2024-12-03 17:29:58 GMT+08:00}]  
SERVER_ID    IP_PORT    MATCH_INDEX    NEXT_INDEX    ROLE    HAS_VOTED    FORCE_SYNC    ELECTION_WEIGHT    LEARNER_SOURCE    APPLIED_INDEX    PIPELINING    SEND_APPLIED  
1    11.167.60.147:14991    264333    0    Leader    Yes    N- 9    0    264332    N- No  
2    11.167.60.147:14992    264333    264334    Follower    Yes    N- 9    0    264333    Yes    No  
3    11.167.60.147:14993    264333    264334    Follower    Yes    N- 1    0    264333    Yes    No  

# 再度実行します。クラスタ情報は変更されていないため、関連情報は出力されません（クラスタ情報はキャッシュされ、初期化を高速化します）。 $java -cp . :mysql-connector-j-8.0.33.jar:polardbx-connector-java-2.1.2.jar TestDriver  
SERVER_ID    IP_PORT    MATCH_INDEX    NEXT_INDEX    ROLE    HAS_VOTED    FORCE_SYNC    ELECTION_WEIGHT    LEARNER_SOURCE    APPLIED_INDEX    PIPELINING    SEND_APPLIED  
1    11.167.60.147:14991    264333    0    Leader    Yes    N- 9    0    264332    N- No  
2    11.167.60.147:14992    264333    264334    Follower    Yes    N- 9    0    264333    Yes    No  
3    11.167.60.147:14993    264333    264334    Follower    Yes    N- 1    0    264333    Yes    No  
</div>