すべてのプロダクト
Search
ドキュメントセンター

Hologres:JDBC

最終更新日:Aug 23, 2026

Hologres は PostgreSQL のワイヤープロトコルと互換性があるため、PostgreSQL JDBC Driver を使用する任意のツールまたはアプリケーションから接続できます。このガイドでは、JDBC 接続の設定、データの書き込みとクエリ、パフォーマンスチューニングについて説明します。

このページの内容

前提条件

開始する前に、次の項目を用意してください:

  • データベースが作成済みの Hologres インスタンス

  • インスタンスのエンドポイント、ポート、データベース名 (Hologres コンソールの[インスタンス詳細]ページの[ネットワーク情報]で確認できます)

  • AccessKey ID と AccessKey シークレット

注意事項

  • PostgreSQL JDBC Driver 42.3.2 以降を使用してください。このバージョンでは CVE-2022-21724 の脆弱性が修正されています。これより前のバージョンにはセキュリティリスクがあります。

  • 書き込みパフォーマンステストでは Virtual Private Cloud (VPC) ネットワークを使用してください。パブリックネットワークでは、パフォーマンステストのベンチマークを満たせません。

  • Hologres は、同一トランザクション内で DDL と書き込み操作を混在させることをサポートしていません。DDL と書き込み操作は別々のトランザクションで実行してください。混在させると、ERROR: INSERT in ddl transaction is not supported now. エラーが返されます。

    autoCommit は true のままにしてください。これは JDBC のデフォルト値であるため、コード内で明示的に commit を呼び出さないでください:

    Connection conn = DriverManager.getConnection(url, user, password);
    conn.setAutoCommit(true);
  • Hologres の書き込み操作はロールバックできません。Connection.rollback() でも、SQL の ROLLBACK ステートメントでも、すでに実行済みの INSERT、UPDATE、DELETE は取り消せません。また、書き込みは直ちに反映されます。つまり、commit 前でも他の接続から参照可能です。

    障害補償に JDBC トランザクションを使用しないでください。代わりに、アプリケーション側でべき等性または調整を実装してください。たとえば、INSERT ON CONFLICT を使用してリトライをべき等にできます。

JDBC を使用した Hologres への接続

手順 1:ドライバーの依存関係の追加

多くの SQL クライアントツールには PostgreSQL ドライバーが組み込まれています。利用できる場合は、それを使用してください。Java アプリケーションの場合は、Maven プロジェクトに PostgreSQL JDBC Driver を追加します。jdbc.postgresql.org/download からダウンロードし、バージョン 42.3.2 以降 (最新の安定版を推奨) を使用してください。

Hologres は標準の PostgreSQL JDBC Driver を使用します。Hologres 専用のドライバーを別途インストールする必要はありません。

次の依存関係を pom.xml に追加します:

<dependencies>
    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <!-- 42.3.2 以降を使用します。最新の安定版を推奨します。 -->
        <version>42.7.13</version>
    </dependency>
</dependencies>

手順 2:接続文字列の作成

接続文字列の形式は次のとおりです:

jdbc:postgresql://<ENDPOINT>:<PORT>/<DBNAME>?user=<ACCESS_ID>&password=<ACCESS_KEY>

必須パラメーター

パラメーター

説明

<ENDPOINT>

Hologres インスタンスのネットワークアドレスです。コンソールでは、アドレスとポートが <ENDPOINT>:<PORT> の形式で 1 つの値としてまとめて提供されます。コロンの前がエンドポイントです。Hologres コンソールの [インスタンス詳細] ページで、ネットワーク情報 セクションに移動し、コードが実行されるネットワーク環境に一致する ネットワークタイプ を選択して、その ドメイン名 をコピーします。ネットワークタイプが一致しないと、接続に失敗します。

<PORT>

Hologres インスタンスのポートは、上記の ドメイン名 の値にあるコロン以降の部分です。

<DBNAME>

Hologres 内のデータベース名です。

<ACCESS_ID>

AccessKey ID です。ハードコーディングせず、環境変数に格納してください。

<ACCESS_KEY>

AccessKey シークレットです。ハードコーディングせず、環境変数に格納してください。

オプションパラメーター

必要に応じて、これらを接続文字列に追加します。複数のパラメーターは & で区切ります。

パラメーター

効果

ApplicationName=<name>

接続にアプリケーション名のタグを付け、[slow query checklist] で識別しやすくします。

reWriteBatchedInserts=true

バッチ挿入を 1 つの複数値 INSERT ステートメントに書き換え、書き込みスループットを向上させます。

currentSchema=<schema>

デフォルトのスキーマを設定します。MaxCompute からの外部テーブル自動ロードを有効化した後に外部テーブルをクエリする場合に必要です。MaxCompute のプロジェクト名は、同名のスキーマにマッピングされます。

preferQueryMode=simple

PostgreSQL JDBC ドライバーを、拡張プロトコル (extended、デフォルト) からシンプルプロトコル (simple) に切り替えます。このシナリオに関係する 2 つの値のみを記載しています。全リストについては、PostgreSQL JDBC Driver documentation を参照してください。無効な値は黙って無視され、ドライバーは extended にフォールバックします。このパラメーターを使用するタイミングと副作用については、preferQueryMode について を参照してください。

preferQueryMode について

拡張プロトコルでは、PreparedStatement のパラメーターが明示的な型とともに送信され、ドライバーは暗黙の型変換を行いません。そのため、整数列を varchar パラメーターと比較すると、ERROR: operator does not exist: integer = character varying のようなエラーで失敗する場合があります。この型不一致エラーが発生した場合は、接続文字列に preferQueryMode=simple を追加してください。これにより、ドライバーは SQL をプレーンテキストとして送信し、サーバーがコンテキストからパラメーター型を推論します。

simple を使用すると、ドライバーはサーバーサイドのプリペアドステートメントを使用しなくなります。そのため、プリペアドステートメントモードが依存する SQL コンパイル結果のキャッシュが失われます。高頻度クエリやバッチ書き込みではスループットが目に見えて低下します。これは、本トピックの別の箇所で推奨している「高スループットのためにプリペアドステートメントモードを使用する」という推奨と相反します。

型不一致エラーは、次の優先順で解決してください:

  1. 列の型に一致する setter を使用します。たとえば、INT 列には setInt を使用し、setString は使用しません。

  2. または、SQL 内でパラメーターを明示的にキャストします。例:where id = ?::int

  3. サードパーティの ORM や BI ツールなど、呼び出し側コードを変更できない場合に限り、preferQueryMode=simple を使用します。バッチ書き込み性能も必要な場合は、reWriteBatchedInserts=true と組み合わせることができます。これら 2 つは併用できます。

推奨オプションを有効化した接続文字列の例:

jdbc:postgresql://<ENDPOINT>:<PORT>/<DBNAME>?user=<ACCESS_ID>&password=<ACCESS_KEY>&ApplicationName=myApp&reWriteBatchedInserts=true

PreparedStatement クエリが、クエリパラメーターと列の型不一致により ERROR: operator does not exist: integer = character varying のようなエラーで失敗する場合は、接続文字列に preferQueryMode=simple を追加してください:

jdbc:postgresql://<ENDPOINT>:<PORT>/<DBNAME>?user=<ACCESS_ID>&password=<ACCESS_KEY>&preferQueryMode=simple

手順 3:環境変数への認証情報の格納

接続文字列に認証情報をハードコーディングすると、セキュリティリスクになります。代わりに環境変数に格納してください。Linux の場合は、次の内容を ~/.bash_profile に追加します:

export ALIBABA_CLOUD_USER=<ACCESS_ID>
export ALIBABA_CLOUD_PASSWORD=<ACCESS_KEY>

手順 4:接続してクエリを実行

接続がハングしないように、socketTimeout、loginTimeout、tcpKeepAlive を設定してください。これらは PGProperty では SOCKET_TIMEOUT、LOGIN_TIMEOUT、TCP_KEEP_ALIVE として公開されています。次の例を参照してください。

次の例では、環境変数から認証情報を読み取り、タイムアウトプロパティを設定し、Hologres に接続して、標準の Statement を使用して基本的な SELECT クエリを実行します:

import org.postgresql.PGProperty;

import java.sql.*;
import java.util.Properties;

public class HologresTest {

    private void jdbcExample() throws SQLException {
        String user = System.getenv("ALIBABA_CLOUD_USER");
        String password = System.getenv("ALIBABA_CLOUD_PASSWORD");
        String url = String.format(
            "jdbc:postgresql://<ENDPOINT>:<PORT>/<DBNAME>?currentSchema=<SCHEMA_NAME>&user=%s&password=%s",
            user, password
        );
        Properties props = new Properties();
        // 実際のクエリ実行時間に基づいて SOCKET_TIMEOUT を設定し、
        // クエリ完了前にタイムアウトしないようにします。
        PGProperty.SOCKET_TIMEOUT.set(props, 3600);
        PGProperty.LOGIN_TIMEOUT.set(props, 60);
        PGProperty.TCP_KEEP_ALIVE.set(props, true);
        try (Connection conn = DriverManager.getConnection(url, props)) {
            try (Statement st = conn.createStatement()) {
                String sql = "SELECT pk, f1 FROM test_tb WHERE pk > 0 LIMIT 100";
                try (ResultSet rs = st.executeQuery(sql)) {
                    while (rs.next()) {
                        // 1 列目の値を読み取ります
                        String c1 = rs.getString(1);
                    }
                }
            }
        }
    }
}

データの書き込みとクエリ

データの書き込み

JDBC では、Statement またはプリペアドステートメントモードを使用してデータを書き込めます。書き込み操作にはプリペアドステートメントモードを使用してください。このモードでは、サーバーが SQL コンパイル結果をキャッシュするため、書き込みレイテンシが低減し、スループットが向上します。バッチサイズは 256 の倍数に設定してください。推奨される最小バッチサイズは 256 です。

このセクションの例では、次のテーブルを使用します。あらかじめデータベースに作成してください。

CREATE TABLE test_tb (
    pk int PRIMARY KEY,
    f1 text,
    f2 timestamptz,
    f3 double precision
);

バッチ挿入

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.text.SimpleDateFormat;

/*
 * プリペアドステートメントモードでデータをバッチ書き込みします。
 * バッチサイズ:256 行(推奨される最小値)。
 */
private static void writeBatchWithPreparedStatement(Connection conn) throws Exception {
    try (PreparedStatement stmt = conn.prepareStatement("insert into test_tb values (?,?,?,?)")) {
        int batchSize = 256;
        for (int i = 0; i < batchSize; ++i) {
            stmt.setInt(1, 1000 + i);
            stmt.setString(2, "1");
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
            java.util.Date parsedDate = dateFormat.parse("1990-11-11 00:00:00");
            stmt.setTimestamp(3, new java.sql.Timestamp(parsedDate.getTime()));
            stmt.setDouble(4, 0.1);
            stmt.addBatch();
        }
        stmt.executeBatch();
    }
}

INSERT ON CONFLICT を使用した Upsert

競合時に既存行を更新するには、PostgreSQL の INSERT ON CONFLICT 構文を使用します。宛先テーブルにはプライマリキーが必要です。

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.text.SimpleDateFormat;

private static void insertOverwrite(Connection conn) throws Exception {
    try (PreparedStatement stmt = conn.prepareStatement(
        "insert into test_tb values (?,?,?,?), (?,?,?,?), (?,?,?,?), (?,?,?,?), (?,?,?,?), (?,?,?,?) " +
        "on conflict(pk) do update set f1 = excluded.f1, f2 = excluded.f2, f3 = excluded.f3"
    )) {
        int batchSize = 6;
        for (int i = 0; i < batchSize; ++i) {
            stmt.setInt(i * 4 + 1, i);
            stmt.setString(i * 4 + 2, "1");
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
            java.util.Date parsedDate = dateFormat.parse("1990-11-11 00:00:00");
            stmt.setTimestamp(i * 4 + 3, new java.sql.Timestamp(parsedDate.getTime()));
            stmt.setDouble(i * 4 + 4, 0.1);
        }
        int affectedRows = stmt.executeUpdate();
        System.out.println("affected rows => " + affectedRows);
    }
}

次の例では、書き込み操作にプリペアドステートメントモードを使用し、繰り返しの INSERT でのスループットを向上させます:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.UUID;

private void jdbcPreparedStmtExample() throws SQLException {
    String user = System.getenv("ALIBABA_CLOUD_USER");
    String password = System.getenv("ALIBABA_CLOUD_PASSWORD");
    String url = String.format(
        "jdbc:postgresql://<ENDPOINT>:<PORT>/<DBNAME>?currentSchema=<SCHEMA_NAME>&user=%s&password=%s",
        user, password
    );
    try (Connection conn = DriverManager.getConnection(url)) {
        // 10行を1回の複数値INSERT文で挿入します。
        String sql = "insert into test_tb (pk, f1) values " +
                "(?, ?), (?, ?), (?, ?), (?, ?), (?, ?), " +
                "(?, ?), (?, ?), (?, ?), (?, ?), (?, ?)";
        try (PreparedStatement st = conn.prepareStatement(sql)) {
            for (int j = 0; j < 10; ++j) {
                // 一意のプライマリキーとランダムな文字列を設定します
                st.setInt(j * 2 + 1, 4000 + j);
                st.setString(j * 2 + 2, UUID.randomUUID().toString());
            }
            System.out.println("affected row => " + st.executeUpdate());
        }
    }
}

データのクエリ

Hologres のテーブルからデータをクエリするには、標準の SQL SELECT ステートメントを使用します。手順 4 の基本的な SELECT の例が、このパターンを示しています。

パラメーター化されたクエリには、プリペアドステートメントモードを使用し、列の型に一致する setter でパラメーターを渡してください:

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

private static void queryWithPreparedStatement(Connection conn) throws Exception {
    String sql = "select pk, f1, f2, f3 from test_tb where pk = ?";
    try (PreparedStatement stmt = conn.prepareStatement(sql)) {
        // pk は INT 列のため setInt を使用します。setString で String を渡すと
        // 拡張プロトコルでは次のエラーで失敗します:
        // ERROR: operator does not exist: integer = character varying
        stmt.setInt(1, 1000);
        try (ResultSet rs = stmt.executeQuery()) {
            while (rs.next()) {
                System.out.println(rs.getInt("pk") + ", " + rs.getString("f1"));
            }
        }
    }
}

Druid コネクションプールの設定

Hologres への接続には Druid 1.1.12 以降を使用してください。

使用上の注意:

  • 接続を再利用して接続チャーンを回避するために、keepAlive=true を設定してください。

  • Druid 1.2.12 から 1.2.21 には、connectTimeout と socketTimeout を指定しない場合にデフォルトが 10 秒になる既知の問題があります。該当する場合は、新しいバージョンにアップグレードしてください。

  • インスタンスサイズとワークロードに基づいて、initialSize、minIdle、maxActive を設定してください。

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
      init-method="init" destroy-method="close">
  <!-- コンソールのインスタンス設定ページにあるエンドポイント URL -->
  <property name="url" value="${jdbc_url}" />
  <!-- ユーザーアカウントの AccessKey ID -->
  <property name="username" value="${jdbc_user}" />
  <!-- ユーザーアカウントの AccessKey シークレット -->
  <property name="password" value="${jdbc_password}" />

  <!-- プールサイズ:インスタンスサイズとワークロードに応じて調整します -->
  <property name="initialSize" value="5" />
  <property name="minIdle" value="10" />
  <property name="maxActive" value="20" />

  <!-- プールからの接続取得を最大 60 秒待機します -->
  <property name="maxWait" value="60000" />
  <!-- アイドル接続を 2 秒ごとにチェックします -->
  <property name="timeBetweenEvictionRunsMillis" value="2000" />
  <!-- 10 分以上アイドルの接続を破棄します -->
  <property name="minEvictableIdleTimeMillis" value="600000" />
  <property name="maxEvictableIdleTimeMillis" value="900000" />

  <property name="validationQuery" value="select 1" />
  <property name="testWhileIdle" value="true" />
  <!-- borrow/return 時に接続をテストしません(オーバーヘッドを削減) -->
  <property name="testOnBorrow" value="false" />
  <property name="testOnReturn" value="false" />

  <property name="keepAlive" value="true" />
  <property name="phyMaxUseCount" value="100000" />
  <property name="filters" value="stat" />
</bean>

GUC パラメーターの設定

Grand Unified Configuration (GUC) パラメーターは、タイムアウトなどのセッションレベルの動作を制御します。接続時に PGProperty.OPTIONS を使用して設定します。

次の例では、statement_timeout と idle_in_transaction_session_timeout を 12,345 ミリ秒に設定します:

import org.postgresql.PGProperty;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

public class GucDemo {
    public static void main(String[] args) {
        String hostname = "hgpostcn-cn-xxxx-cn-hangzhou.hologres.aliyuncs.com";
        String port = "80";
        String dbname = "demo";
        String jdbcUrl = "jdbc:postgresql://" + hostname + ":" + port + "/" + dbname;

        Properties properties = new Properties();
        properties.setProperty("user", "xxxxx");
        properties.setProperty("password", "xxxx");

        // セッションレベルの GUC パラメーターを設定します
        PGProperty.OPTIONS.set(properties,
            "--statement_timeout=12345 --idle_in_transaction_session_timeout=12345");

        try {
            Class.forName("org.postgresql.Driver");
            Connection connection = DriverManager.getConnection(jdbcUrl, properties);

            PreparedStatement preparedStatement =
                connection.prepareStatement("show statement_timeout");
            ResultSet resultSet = preparedStatement.executeQuery();
            while (resultSet.next()) {
                ResultSetMetaData rsmd = resultSet.getMetaData();
                int columnCount = rsmd.getColumnCount();
                Map<String, Object> map = new HashMap<>();
                for (int i = 0; i < columnCount; i++) {
                    map.put(rsmd.getColumnName(i + 1).toLowerCase(), resultSet.getObject(i + 1));
                }
                System.out.println(map);
            }
        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }
}

使用可能な GUC パラメーターの一覧については、GUC parameters を参照してください。

パフォーマンスチューニング

書き込みスループットを最大化するには、次の方法を試してください:

  • VPC ネットワークを使用してください。 パブリックネットワークではレイテンシが増加するため、最適な書き込み性能を達成できません。

  • バッチ書き換えを有効にしてください。 接続文字列に reWriteBatchedInserts=true を追加します。これにより、個々の INSERT が 1 つの複数値ステートメントに書き換えられ、スループットが大幅に向上します。

  • プリペアドステートメントモードを使用してください。 サーバーが SQL コンパイル結果をキャッシュし、行あたりのレイテンシを低減します。

  • バッチサイズを 256 の倍数に設定してください。 効果が出る最小バッチサイズは 256 です。倍数を大きくするほど、スループットがさらに向上します。自動バッチ処理には Holo Client を使用してください。

すべてのパフォーマンスオプションを有効化した接続文字列の例:

jdbc:postgresql://<ENDPOINT>:<PORT>/<DBNAME>?ApplicationName=<APPLICATION_NAME>&reWriteBatchedInserts=true

負荷分散

Hologres V1.3 以降では、JDBC で複数の読み取り専用セカンダリインスタンスを設定し、読み取りワークロードを分散できます。設定手順については、「JDBC-based load balancing」をご参照ください。