clickhouse-jdbcは標準のJDBCインターフェースを実装しています。clickhouse-client上に構築されており、カスタム型マッピング、トランザクションサポート、標準的な同期UPDATEおよびDELETE文などの追加機能を提供するため、レガシーアプリケーションやツールと容易に使用できます。
注記
最新のJDBC(0.7.2)バージョンはClient-V1を使用しています
clickhouse-jdbc APIは同期的であり、一般的にはより多くのオーバーヘッド(例:SQLの解析や型のマッピング/変換など)が発生します。パフォーマンスが重要な場合、またはClickHouseへのより直接的なアクセス方法を希望する場合は、clickhouse-clientの使用を検討してください。
環境要件
セットアップ
<!-- https://mvnrepository.com/artifact/com.clickhouse/clickhouse-jdbc -->
<dependency>
<groupId>com.clickhouse</groupId>
<artifactId>clickhouse-jdbc</artifactId>
<version>0.7.2</version>
<!-- 依存関係をすべて含んだ uber JAR を使用します。より小さい JAR が必要な場合は、classifier を http に変更してください -->
<classifier>shaded-all</classifier>
</dependency>
// https://mvnrepository.com/artifact/com.clickhouse/clickhouse-jdbc
// 依存関係をすべて含んだ uber JAR を使用します。より小さい JAR が必要な場合は、classifier を http に変更してください
implementation("com.clickhouse:clickhouse-jdbc:0.7.2:shaded-all")
// https://mvnrepository.com/artifact/com.clickhouse/clickhouse-jdbc
// 依存関係をすべて含んだ uber JAR を使用します。より小さい JAR が必要な場合は、classifier を http に変更してください
implementation 'com.clickhouse:clickhouse-jdbc:0.7.2:shaded-all'
バージョン 0.5.0 以降、クライアントにバンドルされた Apache HTTP Client を使用しています。このパッケージには共有バージョンが存在しないため、ロガーを依存関係として追加する必要があります。
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.16</version>
</dependency>
// https://mvnrepository.com/artifact/org.slf4j/slf4j-api
implementation("org.slf4j:slf4j-api:2.0.16")
// https://mvnrepository.com/artifact/org.slf4j/slf4j-api
implementation 'org.slf4j:slf4j-api:2.0.16'
ドライバークラス: com.clickhouse.jdbc.ClickHouseDriver
URL構文: jdbc:(ch|clickhouse)[:<protocol>]://endpoint1[,endpoint2,...][/<database>][?param1=value1¶m2=value2][#tag1,tag2,...]、例:
jdbc:ch://localhost は jdbc:clickhouse:http://localhost:8123 と同じです。
jdbc:ch:https://localhost は jdbc:clickhouse:http://localhost:8443?ssl=true&sslmode=STRICT と同等です。
jdbc:ch:grpc://localhost は jdbc:clickhouse:grpc://localhost:9100 と等価です
接続プロパティ:
| プロパティ | デフォルト値 | 説明 |
|---|
continueBatchOnError | false | エラー発生時にバッチ処理を継続するかどうか |
createDatabaseIfNotExist | false | データベースが存在しない場合に自動的に作成するかどうか |
custom_http_headers | | カンマ区切りで指定するカスタム HTTP ヘッダー。例: User-Agent=client1,X-Gateway-Id=123 |
custom_http_params | | カンマ区切りのカスタム HTTP クエリパラメータ。例:extremes=0,max_result_rows=100 |
nullAsDefault | 0 | 0 - null 値をそのまま扱い、Nullable でないカラムに null を挿入した場合は例外をスローする; 1 - null 値をそのまま扱い、挿入時の null チェックを無効にする; 2 - クエリおよび挿入の両方で、null を対応するデータ型のデフォルト値に置き換える |
jdbcCompliance | true | 標準的な同期型 UPDATE/DELETE および疑似トランザクションをサポートするかどうか |
typeMappings | | ClickHouse のデータ型と Java クラスの対応付けをカスタマイズします。これは、getColumnType() および getObject(Class<>?>) の両方の戻り値に影響します。例: UInt128=java.lang.String,UInt256=java.lang.String |
wrapperObject | false | getObject() が Array 型 / Tuple 型に対して java.sql.Array / java.sql.Struct を返すかどうか。 |
注記: 詳細はJDBC固有の設定を参照してください。
サポートされるデータ型
JDBCドライバは、クライアントライブラリと同じデータ形式をサポートしています。
注記
- AggregatedFunction - ⚠️
SELECT * FROM table ... はサポートしていません
- Decimal - 一貫性のため、21.9+ では
SET output_format_decimal_trailing_zeros=1 を使用
- Enum - 文字列型および整数型の両方として扱える
- UInt64 - client-v1 では
long にマップされます
接続の作成
String url = "jdbc:ch://my-server/system"; // use http protocol and port 8123 by default
Properties properties = new Properties();
ClickHouseDataSource dataSource = new ClickHouseDataSource(url, properties);
try (Connection conn = dataSource.getConnection("default", "password");
Statement stmt = conn.createStatement()) {
}
単純なステートメント
try (Connection conn = dataSource.getConnection(...);
Statement stmt = conn.createStatement()) {
ResultSet rs = stmt.executeQuery("select * from numbers(50000)");
while(rs.next()) {
// ...
}
}
Insert
注記
Statement ではなく PreparedStatement を使用する
使用は容易ですが、input関数と比較してパフォーマンスが劣ります(以下を参照):
try (PreparedStatement ps = conn.prepareStatement("insert into mytable(* except (description))")) {
ps.setString(1, "test"); // id
ps.setObject(2, LocalDateTime.now()); // timestamp
ps.addBatch(); // parameters will be write into buffered stream immediately in binary format
...
ps.executeBatch(); // stream everything on-hand into ClickHouse
}
高いパフォーマンス特性を持つオプション:
try (PreparedStatement ps = conn.prepareStatement(
"insert into mytable select col1, col2 from input('col1 String, col2 DateTime64(3), col3 Int32')")) {
// The column definition will be parsed so the driver knows there are 3 parameters: col1, col2 and col3
ps.setString(1, "test"); // col1
ps.setObject(2, LocalDateTime.now()); // col2, setTimestamp is slow and not recommended
ps.setInt(3, 123); // col3
ps.addBatch(); // parameters will be write into buffered stream immediately in binary format
...
ps.executeBatch(); // stream everything on-hand into ClickHouse
}
プレースホルダーを使用した挿入
このオプションは小規模な挿入にのみ推奨されます。長いSQL式が必要となり、クライアント側で解析されてCPUとメモリを消費するためです:
try (PreparedStatement ps = conn.prepareStatement("insert into mytable values(trim(?),?,?)")) {
ps.setString(1, "test"); // id
ps.setObject(2, LocalDateTime.now()); // timestamp
ps.setString(3, null); // description
ps.addBatch(); // append parameters to the query
...
ps.executeBatch(); // issue the composed query: insert into mytable values(...)(...)...(...)
}
DateTimeとタイムゾーンの取り扱い
java.sql.Timestampの代わりにjava.time.LocalDateTimeまたはjava.time.OffsetDateTimeを、java.sql.Dateの代わりにjava.time.LocalDateを使用してください。
try (PreparedStatement ps = conn.prepareStatement("select date_time from mytable where date_time > ?")) {
ps.setObject(2, LocalDateTime.now());
ResultSet rs = ps.executeQuery();
while(rs.next()) {
LocalDateTime dateTime = (LocalDateTime) rs.getObject(1);
}
...
}
AggregateFunctionの取り扱い
注記
現時点では、groupBitmap のみサポートされています。
// batch insert using input function
try (ClickHouseConnection conn = newConnection(props);
Statement s = conn.createStatement();
PreparedStatement stmt = conn.prepareStatement(
"insert into test_batch_input select id, name, value from input('id Int32, name Nullable(String), desc Nullable(String), value AggregateFunction(groupBitmap, UInt32)')")) {
s.execute("drop table if exists test_batch_input;"
+ "create table test_batch_input(id Int32, name Nullable(String), value AggregateFunction(groupBitmap, UInt32))engine=Memory");
Object[][] objs = new Object[][] {
new Object[] { 1, "a", "aaaaa", ClickHouseBitmap.wrap(1, 2, 3, 4, 5) },
new Object[] { 2, "b", null, ClickHouseBitmap.wrap(6, 7, 8, 9, 10) },
new Object[] { 3, null, "33333", ClickHouseBitmap.wrap(11, 12, 13) }
};
for (Object[] v : objs) {
stmt.setInt(1, (int) v[0]);
stmt.setString(2, (String) v[1]);
stmt.setString(3, (String) v[2]);
stmt.setObject(4, v[3]);
stmt.addBatch();
}
int[] results = stmt.executeBatch();
...
}
// use bitmap as query parameter
try (PreparedStatement stmt = conn.prepareStatement(
"SELECT bitmapContains(my_bitmap, toUInt32(1)) as v1, bitmapContains(my_bitmap, toUInt32(2)) as v2 from {tt 'ext_table'}")) {
stmt.setObject(1, ClickHouseExternalTable.builder().name("ext_table")
.columns("my_bitmap AggregateFunction(groupBitmap,UInt32)").format(ClickHouseFormat.RowBinary)
.content(new ByteArrayInputStream(ClickHouseBitmap.wrap(1, 3, 5).toBytes()))
.asTempTable()
.build());
ResultSet rs = stmt.executeQuery();
Assert.assertTrue(rs.next());
Assert.assertEquals(rs.getInt(1), 1);
Assert.assertEquals(rs.getInt(2), 0);
Assert.assertFalse(rs.next());
}
HTTPライブラリの設定
ClickHouse JDBCコネクタは、以下の3つのHTTPライブラリをサポートしています:HttpClient、HttpURLConnection、およびApache HttpClient。
注記
HttpClientはJDK 11以降でのみサポートされています。
JDBCドライバーはデフォルトでHttpClientを使用します。ClickHouse JDBCコネクタが使用するHTTPライブラリを変更するには、以下のプロパティを設定します:
properties.setProperty("http_connection_provider", "APACHE_HTTP_CLIENT");
対応する値の一覧は以下の通りです:
| プロパティ値 | HTTP ライブラリ |
|---|
| HTTP_CLIENT | HttpClient |
| HTTP_URL_CONNECTION | HttpURLConnection |
| APACHE_HTTP_CLIENT | Apache HttpClient |
SSLでClickHouseに接続する
SSLを使用してClickHouseへのセキュアなJDBC接続を確立するには、JDBCプロパティにSSLパラメータを含めるよう設定する必要があります。通常、これにはJDBC URLまたはPropertiesオブジェクトにsslmodeやsslrootcertなどのSSLプロパティを指定することが含まれます。
SSL プロパティ
| 名前 | デフォルト値 | 指定可能な値 | 説明 |
|---|
ssl | false | true, false | 接続に対して SSL/TLS を有効にするかどうか |
sslmode | strict | strict, none | SSL/TLS 証明書を検証するかどうか |
sslrootcert | | | SSL/TLS ルート証明書のパス |
sslcert | | | SSL/TLS 証明書ファイルへのパス |
sslkey | | | PKCS#8 形式の RSA 鍵 |
key_store_type | | JKS, PKCS12 | KeyStore/TrustStore ファイルの種別または形式を指定します |
trust_store | | | TrustStore ファイルのパス |
key_store_password | | | KeyStore 設定で指定された KeyStore ファイルにアクセスするためのパスワード |
これらのプロパティにより、JavaアプリケーションがClickHouseサーバーと暗号化接続で通信することが保証され、転送中のデータセキュリティが強化されます。
String url = "jdbc:ch://your-server:8443/system";
Properties properties = new Properties();
properties.setProperty("ssl", "true");
properties.setProperty("sslmode", "strict"); // NONE to trust all servers; STRICT for trusted only
properties.setProperty("sslrootcert", "/mine.crt");
try (Connection con = DriverManager
.getConnection(url, properties)) {
try (PreparedStatement stmt = con.prepareStatement(
// place your code here
}
}
大量挿入時のJDBCタイムアウトの解決
ClickHouseで実行時間の長い大規模なインサート処理を実行する際、次のようなJDBCタイムアウトエラーが発生することがあります:
Caused by: java.sql.SQLException: Read timed out, server myHostname [uri=https://hostname.aws.clickhouse.cloud:8443]
これらのエラーはデータ挿入プロセスを中断し、システムの安定性に影響を与える可能性があります。この問題に対処するには、クライアントOS上でいくつかのタイムアウト設定を調整する必要があります。
Mac OS
macOSでは、以下の設定を調整することで問題を解決できます:
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におけるソケットキープアライブ設定の処理方法の違いにより、追加の手順が必要となります。以下の手順に従ってください:
/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 秒からこの値を下げることを検討してもよいでしょう)
- カーネルパラメータを変更したら、次のコマンドを実行して変更を適用します。
これらの設定を行った後、クライアントがソケット上でKeep Aliveオプションを有効にしていることを確認してください:
properties.setProperty("socket_keepalive", "true");
注記
現在、ソケットのキープアライブを設定する際には、Apache HTTP Clientライブラリを使用する必要があります。clickhouse-javaがサポートする他の2つのHTTPクライアントライブラリでは、ソケットオプションの設定が許可されていないためです。詳細なガイドについては、HTTPライブラリの設定を参照してください。
または、JDBC URLに同等のパラメータを追加することもできます。
JDBCドライバーのデフォルトのソケットおよび接続タイムアウトは30秒です。大量データの挿入操作をサポートするために、タイムアウトを増やすことができます。ClickHouseClientのoptionsメソッドを使用し、ClickHouseClientOptionで定義されているSOCKET_TIMEOUTおよびCONNECTION_TIMEOUTオプションを指定してください:
final int MS_12H = 12 * 60 * 60 * 1000; // 12 h in ms
final String sql = "insert into table_a (c1, c2, c3) select c1, c2, c3 from table_b;";
try (ClickHouseClient client = ClickHouseClient.newInstance(ClickHouseProtocol.HTTP)) {
client.read(servers).write()
.option(ClickHouseClientOption.SOCKET_TIMEOUT, MS_12H)
.option(ClickHouseClientOption.CONNECTION_TIMEOUT, MS_12H)
.query(sql)
.executeAndWait();
}