メインコンテンツへスキップ
メインコンテンツへスキップ

JDBC ドライバー

注記

clickhouse-jdbc は、最新の Java クライアントを用いて標準的な JDBC インターフェースを実装しています。 パフォーマンスや直接アクセスが重要な場合は、最新の Java クライアントを直接使用することを推奨します。

0.7.x からの変更点

0.8 では、ドライバーが JDBC 仕様により厳密に従うようにすることを目指したため、影響が出る可能性のある削除された機能があります:

旧機能備考
トランザクションサポートドライバーの初期バージョンでは、トランザクションサポートは 擬似的に 実装されており、予期しない結果を招く可能性がありました。
レスポンス列名の変更ResultSet は変更可能でしたが、効率性の観点から現在は読み取り専用になっています。
複数ステートメント SQL複数ステートメントのサポートは 擬似的に 実装されていただけであり、現在は 1 回の呼び出しにつき 1 ステートメントのみを厳密にサポートする実装になっています。
名前付きパラメータJDBC 仕様の一部ではありません。
ストリームベースの PreparedStatementドライバーの初期バージョンでは、PreparedStatement を JDBC 以外の用途で使用することが可能でした。そのようなオプションを希望する場合は、Java Client およびその examples を参照することを推奨します。
注記

Date はタイムゾーンなしで保存される一方、DateTime はタイムゾーン付きで保存されます。注意しないと予期しない結果を招く可能性があります。

環境要件

セットアップ

<!-- https://mvnrepository.com/artifact/com.clickhouse/clickhouse-jdbc -->
<dependency>
    <groupId>com.clickhouse</groupId>
    <artifactId>clickhouse-jdbc</artifactId>
    <version>0.9.1</version>
    <classifier>shaded-all</classifier>
</dependency>

設定

Driver Class: com.clickhouse.jdbc.ClickHouseDriver

URL 構文: jdbc:(ch|clickhouse)[:<protocol>]://endpoint1[,endpoint2,...][/<database>][?param1=value1&param2=value2][#tag1,tag2,...]。例:

  • jdbc:clickhouse:http://localhost:8123
  • jdbc:clickhouse:https://localhost:8443?ssl=true

接続プロパティ:

標準的な JDBC プロパティに加えて、ドライバは基盤となる Java クライアント が提供する ClickHouse 固有のプロパティをサポートします。 可能な場合、サポートされていない機能に対しては、メソッドは SQLFeatureNotSupportedException をスローします。その他のカスタムプロパティには次のものがあります:

PropertyDefault説明
disable_frameworks_detectiontrueUser-Agent 用のフレームワーク検出を無効にする
jdbc_ignore_unsupported_valuesfalseSQLFeatureNotSupportedException のスローを抑制する
clickhouse.jdbc.v1false新しい JDBC の代わりに古い JDBC 実装を使用する
default_query_settingsnullクエリ実行時にデフォルトのクエリ設定を渡せるようにする
jdbc_resultset_auto_closetrueStatement がクローズされたときに ResultSet を自動的にクローズする
beta.row_binary_for_simple_insertfalseRowBinary writer に基づく PreparedStatement 実装を使用する。INSERT INTO ... VALUES クエリでのみ動作する。

サポートされているデータ型

JDBC ドライバーは、基盤となっている Java クライアント と同じデータ形式をサポートします。

日付、時刻、タイムゾーンの扱い

java.sql.Datejava.sql.Timejava.sql.Timestamp はタイムゾーンの計算を複雑にする原因となり得ます。もちろんサポートはされていますが、 java.time パッケージの利用を検討することをお勧めします。ZonedDateTimeOffsetDateTime は、java.sql.Timestampjava.sql.Datejava.sql.Time を置き換える優れた選択肢です。

接続の作成

String url = "jdbc:ch://my-server:8123/system";

Properties properties = new Properties();
DataSource dataSource = new DataSource(url, properties);//DataSourceまたはDriverManagerが主要なエントリポイントです
try (Connection conn = dataSource.getConnection()) {
... // 接続で何らかの処理を行う

認証情報と設定の提供

String url = "jdbc:ch://localhost:8123?jdbc_ignore_unsupported_values=true&socket_timeout=10";

Properties info = new Properties();
info.put("user", "default");
info.put("password", "password");
info.put("database", "some_db");

//DataSourceで接続を作成
DataSource dataSource = new DataSource(url, info);
try (Connection conn = dataSource.getConnection()) {
... // 接続で処理を実行
}

//DriverManagerを使用する別の方法
try (Connection conn = DriverManager.getConnection(url, info)) {
... // 接続で処理を実行
}

シンプルなステートメント


try (Connection conn = dataSource.getConnection(...);
    Statement stmt = conn.createStatement()) {
    ResultSet rs = stmt.executeQuery("select * from numbers(50000)");
    while(rs.next()) {
        // ...
    }
}

INSERT 文

try (PreparedStatement ps = conn.prepareStatement("INSERT INTO mytable VALUES (?, ?)")) {
    ps.setString(1, "test"); // id
    ps.setObject(2, LocalDateTime.now()); // timestamp
    ps.addBatch();
    ...
    ps.executeBatch(); // 保持しているすべてのデータをClickHouseにストリーミング
}

HikariCP

// コネクションプーリングはパフォーマンス面であまり効果がありません。
// なぜなら、基盤となる実装が独自のプールを持っているためです。
// 例: HttpURLConnection はソケット用のプールを持っています
HikariConfig poolConfig = new HikariConfig();
poolConfig.setConnectionTimeout(5000L);
poolConfig.setMaximumPoolSize(20);
poolConfig.setMaxLifetime(300_000L);
poolConfig.setDataSource(new ClickHouseDataSource(url, properties));

try (HikariDataSource ds = new HikariDataSource(poolConfig);
     Connection conn = ds.getConnection();
     Statement s = conn.createStatement();
     ResultSet rs = s.executeQuery("SELECT * FROM system.numbers LIMIT 3")) {
    while (rs.next()) {
        // 行を処理
        log.info("Integer: {}, String: {}", rs.getInt(1), rs.getString(1));//同じカラムだが異なる型
    }
}

詳細情報

詳細については、GitHub リポジトリおよび Java クライアントのドキュメントを参照してください。

トラブルシューティング

ロギング

ドライバーはログ出力に slf4j を使用し、classpath 上で最初に見つかった利用可能な実装を使用します。

大量挿入時の JDBC タイムアウトの解消

ClickHouse に対して実行時間の長い大量挿入処理を行う際、次のような JDBC タイムアウトエラーが発生する場合があります:

原因: java.sql.SQLException: 読み取りタイムアウト、サーバー myHostname [uri=https://hostname.aws.clickhouse.cloud:8443]

これらのエラーはデータ挿入処理を妨げ、システムの安定性に影響を与える可能性があります。この問題に対処するには、クライアント OS 側のいくつかのタイムアウト設定を調整する必要が生じる場合があります。

Mac OS

Mac OS では、次の設定を調整することで問題を解消できます。

  • net.inet.tcp.keepidle: 60000
  • net.inet.tcp.keepintvl: 45000
  • net.inet.tcp.keepinit: 45000
  • net.inet.tcp.keepcnt: 8
  • net.inet.tcp.always_keepalive: 1

Linux

Linux では、同等の設定だけでは問題が解決しない場合があります。Linux におけるソケットのキープアライブ設定の扱いが異なるため、追加の手順が必要です。次の手順に従ってください。

  1. /etc/sysctl.conf や関連する設定ファイルで、次の Linux カーネルパラメータを調整します:
  • net.inet.tcp.keepidle: 60000
  • net.inet.tcp.keepintvl: 45000
  • net.inet.tcp.keepinit: 45000
  • net.inet.tcp.keepcnt: 8
  • net.inet.tcp.always_keepalive: 1
  • net.ipv4.tcp_keepalive_intvl: 75
  • net.ipv4.tcp_keepalive_probes: 9
  • net.ipv4.tcp_keepalive_time: 60(デフォルトの 300 秒からこの値を下げることを検討してください)
  1. カーネルパラメータを変更したら、次のコマンドを実行して変更を反映します:
sudo sysctl -p

これらの設定を行ったら、クライアント側でソケットの Keep Alive オプションが有効になっていることを確認してください。

properties.setProperty("socket_keepalive", "true");