JDBC ドライバー
clickhouse-jdbcは最新のJavaクライアントを使用して標準JDBCインターフェースを実装しています。
パフォーマンスまたは直接アクセスが重要な場合は、最新のJavaクライアントを直接使用することを推奨します。
環境要件
- OpenJDK バージョン 8 以上
セットアップ
- Maven
- Gradle (Kotlin)
- Gradle
設定
ドライバークラス: com.clickhouse.jdbc.ClickHouseDriver
com.clickhouse.jdbc.ClickHouseDriverは、新旧のJDBC実装に対するファサードクラスです。デフォルトでは新しいJDBC実装が使用されます。
接続プロパティでclickhouse.jdbc.v1プロパティをtrueに設定することにより、古いJDBC実装を使用できます。
com.clickhouse.jdbc.Driver is new JDBC implementation.
com.clickhouse.jdbc.DriverV1は旧JDBC実装です。
URL構文: jdbc:(ch|clickhouse)[:<protocol>]://endpoint[:port][/<database>][?param1=value1¶m2=value2][#tag1,tag2,...]、例:
jdbc:clickhouse:http://localhost:8123jdbc:clickhouse:https://localhost:8443?ssl=true
URL構文に関して、以下の点に注意してください:
- URL には エンドポイントを 1 つだけ 指定できます
- プロトコルがデフォルトの 'HTTP' でない場合は、明示的に指定する必要があります
- デフォルトの '8123' 以外のポートを使用する場合は、そのポート番号を明示的に指定する必要があります
- ドライバはポート番号からプロトコルを推測しないため、必ずプロトコルを明示的に指定してください
- プロトコルを指定している場合は、
sslパラメータは不要です。
接続プロパティ
主要な設定パラメータはJavaクライアントで定義されています。これらはそのままドライバに渡してください。ドライバには、クライアント設定には含まれない独自のプロパティがあり、以下に記載されています。
ドライバープロパティ:
| プロパティ | デフォルト値 | 説明 |
|---|---|---|
disable_frameworks_detection | true | User-Agent に基づいたフレームワーク検出を無効化する |
jdbc_ignore_unsupported_values | false | ドライバーの動作に影響しない箇所では SQLFeatureNotSupportedException を抑制します |
clickhouse.jdbc.v1 | false | 新しい JDBC 実装ではなく、旧 JDBC 実装を使用する |
default_query_settings | null | クエリ操作に対してデフォルトのクエリ設定を渡せるようにする |
jdbc_resultset_auto_close | true | Statement のクローズ時に ResultSet を自動的にクローズします |
beta.row_binary_for_simple_insert | false | RowBinary writer ベースの PreparedStatement 実装を使用します。INSERT INTO ... VALUES クエリでのみ使用できます。 |
jdbc_resultset_auto_close | true | Statement のクローズ時に ResultSet を自動的にクローズします |
jdbc_use_max_result_rows | false | サーバープロパティ max_result_rows を使用して、クエリが返す行数を制限できるようにします。有効にすると、ユーザー設定のオーバーフローモードを上書きします。詳細は JavaDoc を参照してください。 |
jdbc_sql_parser | JAVACC | 使用する SQL パーサーを構成します。指定可能な値: ANTLR4, ANTLR4_PARAMS_PARSER, JAVACC。 |
設定例:
以下のJDBC URLと同等になります:
注記: JDBC URLやプロパティをURLエンコードする必要はありません。自動的にエンコードされます。
サポートされるデータ型
JDBCドライバは、基盤となるJavaクライアントと同じデータ形式をサポートしています。
JDBC型マッピング
以下のマッピングが適用されます:
ResultSet#getObject(columnIndex)メソッドは、対応する Java クラスのオブジェクトを返します(Int8->java.lang.Byte、Int16->java.lang.Shortなど)。ResultSetMetaData#getColumnType(columnIndex)メソッドは対応する JDBC 型を返します(Int8->java.lang.Byte、Int16->java.lang.Shortなど)。
マッピングを変更する方法はいくつかあります:
ResultSet#getObject(columnIndex, class)- メソッドは値をclass型に変換しようと試みます。この変換にはいくつか制限があります。詳細は各セクションを参照してください。
数値型
| ClickHouse型 | JDBC型 | Javaクラス |
|---|---|---|
| Int8 | TINYINT | java.lang.Byte |
| Int16 | SMALLINT | java.lang.Short |
| Int32 | INTEGER | java.lang.Integer |
| Int64 | BIGINT | java.lang.Long |
| Int128 | OTHER | java.math.BigInteger |
| Int256 | OTHER | java.math.BigInteger |
| UInt8 | OTHER | java.lang.Short |
| UInt16 | OTHER | java.lang.Integer |
| UInt32 | OTHER | java.lang.Long |
| UInt64 | OTHER | java.math.BigInteger |
| UInt128 | OTHER | java.math.BigInteger |
| UInt256 | OTHER | java.math.BigInteger |
| Float32 | REAL | java.lang.Float |
| Float64 | DOUBLE | java.lang.Double |
| Decimal32 | DECIMAL | java.math.BigDecimal |
| Decimal64 | DECIMAL | java.math.BigDecimal |
| Decimal128 | DECIMAL | java.math.BigDecimal |
| Decimal256 | DECIMAL | java.math.BigDecimal |
| Bool | BOOLEAN | java.lang.Boolean |
- 数値型は相互に変換可能です。そのため、
Int8をFloat64として取得したり、その逆も可能です:rs.getObject(1, Float64.class)は、Int8カラムの値をFloat64型の値として返します。rs.getLong(1)は、Int8カラムの値をLong型の値として返します。rs.getByte(1)は、Int16カラムの値がByteの範囲に収まる場合、その値をByte型の値として返します。
- より広い型からより狭い型への変換は、データ破損のリスクがあるため推奨されません。
Bool型も数値型として扱うことができます。- すべての数値型は
java.lang.Stringとして読み出すことができます。
文字列型
| ClickHouse型 | JDBC型 | Javaクラス |
|---|---|---|
| String | VARCHAR | java.lang.String |
| FixedString | VARCHAR | java.lang.String |
Stringはjava.lang.String型またはbyte[]型としてのみ取得できます。FixedStringはそのまま読み出されますが、不足分はカラムの長さに達するまでゼロバイト(\0)でパディングされます。(たとえば、FixedString(10)で'John'を指定した場合、'John\0\0\0\0\0\0\0\0\0'として読み取られます。)
Enum型
| ClickHouse型 | JDBC型 | Javaクラス |
|---|---|---|
| Enum8 | OTHER | java.lang.String |
| Enum16 | OTHER | java.lang.String |
Enum8およびEnum16は、デフォルトでjava.lang.Stringにマッピングされます。- Enum の値は、対応する getter メソッドまたは
getObject(columnIndex, Integer.class)メソッドを使用して数値として読み取ることができます。 Enum16は内部的に short にマッピングされ、Enum8は byte にマッピングされます。Enum16を byte として読み取ることは、データ破損のリスクがあるため避けるべきです。- Enum の値は文字列または数値として
PreparedStatementに設定できます。
日付/時刻型
| ClickHouse 型 | JDBC 型 | Java クラス |
|---|---|---|
| Date | DATE | java.sql.Date |
| Date32 | DATE | java.sql.Date |
| DateTime | TIMESTAMP | java.sql.Timestamp |
| DateTime64 | TIMESTAMP | java.sql.Timestamp |
| Time | TIME | java.sql.Time |
| Time64 | TIME | java.sql.Time |
- 日付/時刻型は、JDBC との互換性を高めるために
java.sql型へマッピングされます。ただし、ResultSet#getObject(columnIndex, Class<T>)の第 2 引数に対応するクラスを指定することで、java.time.LocalDate、java.time.LocalDateTime、java.time.LocalTimeを取得することもできます。rs.getObject(1, java.time.LocalDate.class)は、Dateカラムのjava.time.LocalDate型の値を返します。rs.getObject(1, java.time.LocalDateTime.class)は、DateTimeカラムのjava.time.LocalDateTime型の値を返します。rs.getObject(1, java.time.LocalTime.class)は、Timeカラムのjava.time.LocalTime型の値を返します。
Date,Date32,Time,Time64はサーバーのタイムゾーン設定の影響を受けません。DateTime、DateTime64はサーバーまたはセッションのタイムゾーンの影響を受けます。DateTimeおよびDateTime64は、getObject(colIndex, ZonedDateTime.class)を使用することでZonedDateTimeとして取得できます。
コレクション型
| ClickHouse 型 | JDBC 型 | Java クラス |
|---|---|---|
| Array | ARRAY | java.sql.Array |
| Tuple | OTHER | Object[] |
| Map | JAVA_OBJECT | java.util.Map |
Arrayは、JDBC との互換性を保つため、デフォルトではjava.sql.Arrayにマッピングされます。これは、返される配列値に関する情報をより詳細に持たせるためでもあり、型推論に役立ちます。ArrayはgetResultSet()メソッドを実装しており、元の配列と同一の内容を持つjava.sql.ResultSetを返します。- コレクション型は
java.lang.Stringとして読み取ってはいけません。これはデータを表現する適切な方法ではないためです(例: 配列内の文字列値に引用符が付与されないなど)。 Mapは、値はgetObject(columnIndex, Class<T>)メソッドでのみ読み取ることができるため、JAVA_OBJECTにマッピングされます。Mapは名前付きカラムを持たないため、java.sql.Structではありません。
Tupleは異なる型を含み得るため、Listを使うのは適切ではなく、Object[]にマッピングされます。TupleはgetObject(columnIndex, Array.class)メソッドを使用することでArrayとして取得できます。この場合、Array#baseTypeNameはTuple型カラムの定義を返します。
地理型
| ClickHouse 型 | JDBC 型 | Java クラス |
|---|---|---|
| Point | OTHER | double[] |
| Ring | OTHER | double[][] |
| Polygon | OTHER | double[][][] |
| MultiPolygon | OTHER | double[][][][] |
Nullable型とLowCardinality型
NullableとLowCardinalityは、他の型をラップする特殊な型です。Nullableは、ResultSetMetaDataでの型名の返され方に影響します。
特殊型
| ClickHouse 型 | JDBC 型 | Java クラス |
|---|---|---|
| UUID | OTHER | java.util.UUID |
| IPv4 | OTHER | java.net.Inet4Address |
| IPv6 | OTHER | java.net.Inet6Address |
| JSON | OTHER | java.lang.String |
| AggregateFunction | OTHER | (バイナリ表現) |
| SimpleAggregateFunction | (ラップされた型) | (ラップされたクラス) |
UUIDは JDBC の標準型ではありませんが、JDK の一部です。デフォルトでは、getObject()メソッドでjava.util.UUIDが返されます。UUIDは、getObject(columnIndex, String.class)メソッドを使用することで、String型として読み取りおよび書き込みができます。IPv4とIPv6は JDBC 標準の型ではありません。ただし、JDK の一部です。デフォルトでは、getObject()メソッドでjava.net.Inet4Addressとjava.net.Inet6Addressが返されます。getObject(columnIndex, String.class)メソッドを使用すると、IPv4とIPv6をStringとして読み書きできます。
日付、時刻、タイムゾーンの処理
java.sql.Date、java.sql.Time、および java.sql.Timestamp はタイムゾーンの計算を複雑にする可能性があります。これらはもちろんサポートされていますが、
java.time パッケージの使用を検討してください。ZonedDateTime および
OffsetDateTime は、java.sql.Timestamp、java.sql.Date、java.sql.Time の優れた代替手段です。
Date はタイムゾーンなしで保存されますが、DateTime はタイムゾーン付きで保存されます。注意を怠ると予期しない結果を招く可能性があります。
接続の作成
認証情報と設定の指定
単純なステートメント
Insert
HikariCP
詳細情報
詳細については、GitHubリポジトリおよびJavaクライアントのドキュメントを参照してください。
トラブルシューティング
ログ
このドライバはログ記録に slf4j を使用し、classpath 上で最初に利用可能な実装を使用します。
大量挿入時のJDBCタイムアウトの解決
ClickHouseで実行時間の長い大規模なインサート処理を実行する際、次のようなJDBCタイムアウトエラーが発生することがあります:
これらのエラーはデータ挿入プロセスを中断し、システムの安定性に影響を与える可能性があります。この問題に対処するには、クライアントOS上のいくつかのタイムアウト設定を調整する必要がある場合があります。
macOS
macOSでは、以下の設定を調整することで問題を解決できます:
net.inet.tcp.keepidle: 60000net.inet.tcp.keepintvl: 45000net.inet.tcp.keepinit: 45000net.inet.tcp.keepcnt: 8net.inet.tcp.always_keepalive: 1
Linux
Linuxでは、同等の設定のみでは問題が解決しない場合があります。Linuxにおけるソケットキープアライブ設定の処理方法の違いにより、追加の手順が必要です。以下の手順に従ってください:
/etc/sysctl.confまたは関連する設定ファイルで、次の Linux カーネルパラメータを調整します:
net.inet.tcp.keepidle: 60000net.inet.tcp.keepintvl: 45000net.inet.tcp.keepinit: 45000net.inet.tcp.keepcnt: 8net.inet.tcp.always_keepalive: 1net.ipv4.tcp_keepalive_intvl: 75net.ipv4.tcp_keepalive_probes: 9net.ipv4.tcp_keepalive_time: 60(この値をデフォルトの 300 秒から引き下げることを検討してもよいでしょう)
- カーネルパラメータを変更したら、以下のコマンドを実行して変更を適用します。
これらの設定を行った後、クライアントがソケット上でKeep Aliveオプションを有効にしていることを確認する必要があります:
移行ガイド
主な変更点
| 機能 | V1(旧) | V2(新) |
|---|---|---|
| トランザクション対応 | 一部サポートあり | サポートなし |
| レスポンスのカラム名の変更 | 一部サポートあり | サポートなし |
| 複数文 SQL | サポートなし | 利用不可 |
| 名前付きパラメーター | サポートあり | サポートなし(JDBC 仕様に準拠していないため) |
PreparedStatement を用いたデータストリーミング | サポートあり | サポートなし |
- JDBC V2 はより軽量な実装として設計されており、その分一部の機能が削除されています。
- ストリーミングデータは JDBC 仕様および Java の仕様には含まれていないため、JDBC V2 ではサポートされていません。
- JDBC V2 では明示的な構成が必要です。フェイルオーバー用のデフォルト設定はありません。
- プロトコルは URL で明示的に指定する必要があります。ポート番号に基づく暗黙的なプロトコル判別は行われません。
設定の変更
列挙型は2つのみです:
com.clickhouse.jdbc.DriverProperties- ドライバー固有の設定プロパティです。com.clickhouse.client.api.ClientConfigProperties- クライアントの構成プロパティを表します。クライアント構成の変更については、Java クライアントのドキュメントを参照してください。
接続プロパティは次のように解析されます:
- URL はまずプロパティとして解析され、その指定内容が他のすべてのプロパティより優先されます。
- ドライバーのプロパティはクライアント側に渡されません。
- エンドポイント(ホスト、ポート、プロトコル)は URL から解析されます。
例:
データ型の変更
数値型
| ClickHouse 型 | V1 との互換性 | JDBC 型 (V2) | Java クラス (V2) | JDBC 型 (V1) | Java クラス (V1) |
|---|---|---|---|---|---|
| Int8 | ✅ | TINYINT | java.lang.Byte | TINYINT | java.lang.Byte |
| Int16 | ✅ | SMALLINT | java.lang.Short | SMALLINT | java.lang.Short |
| Int32 | ✅ | INTEGER | java.lang.Integer | INTEGER | java.lang.Integer |
| Int64 | ✅ | BIGINT | java.lang.Long | BIGINT | java.lang.Long |
| Int128 | ✅ | OTHER | java.math.BigInteger | OTHER | java.math.BigInteger |
| Int256 | ✅ | OTHER | java.math.BigInteger | OTHER | java.math.BigInteger |
| UInt8 | ❌ | OTHER | java.lang.Short | OTHER | com.clickhouse.data.value.UnsignedByte |
| UInt16 | ❌ | OTHER | java.lang.Integer | OTHER | com.clickhouse.data.value.UnsignedShort |
| UInt32 | ❌ | OTHER | java.lang.Long | OTHER | com.clickhouse.data.value.UnsignedInteger |
| UInt64 | ❌ | OTHER | java.math.BigInteger | OTHER | com.clickhouse.data.value.UnsignedLong |
| UInt128 | ✅ | OTHER | java.math.BigInteger | OTHER | java.math.BigInteger |
| UInt256 | ✅ | OTHER | java.math.BigInteger | OTHER | java.math.BigInteger |
| Float32 | ✅ | REAL | java.lang.Float | REAL | java.lang.Float |
| Float64 | ✅ | DOUBLE | java.lang.Double | DOUBLE | java.lang.Double |
| Decimal32 | ✅ | DECIMAL | java.math.BigDecimal | DECIMAL | java.math.BigDecimal |
| Decimal64 | ✅ | DECIMAL | java.math.BigDecimal | DECIMAL | java.math.BigDecimal |
| Decimal128 | ✅ | DECIMAL | java.math.BigDecimal | DECIMAL | java.math.BigDecimal |
| Decimal256 | ✅ | DECIMAL | java.math.BigDecimal | DECIMAL | java.math.BigDecimal |
| Bool | ✅ | BOOLEAN | java.lang.Boolean | BOOLEAN | java.lang.Boolean |
- 最大の違いは、ポータビリティを高めるために符号なし型が標準的な Java 型にマッピングされる点です。
文字列型
| ClickHouse 型 | V1 との互換性 | JDBC 型 (V2) | Java クラス (V2) | JDBC 型 (V1) | Java クラス (V1) |
|---|---|---|---|---|---|
| String | ✅ | VARCHAR | java.lang.String | VARCHAR | java.lang.String |
| FixedString | ✅ | VARCHAR | java.lang.String | VARCHAR | java.lang.String |
FixedStringは両方のバージョンで、そのままの値として読み取られます。たとえば'John'に対するFixedString(10)は'John\0\0\0\0\0\0\0\0\0'として読み込まれます。PreparedStatement#setBytesが使用されると、unhex('<hex_string>')に変換され、その後String型として扱われます。
日付/時刻型
| ClickHouse 型 | 変更有無 | JDBC 型 (V2) | Java クラス (V2) | JDBC 型 (V1) | Java クラス (V1) |
|---|---|---|---|---|---|
| Date | ❌ | DATE | java.sql.Date | DATE | java.time.LocalDate |
| Date32 | ❌ | DATE | java.sql.Date | DATE | java.time.LocalDate |
| DateTime | ❌ | TIMESTAMP | java.sql.Timestamp | TIMESTAMP | java.time.OffsetDateTime |
| DateTime64 | ❌ | TIMESTAMP | java.sql.Timestamp | TIMESTAMP | java.time.OffsetDateTime |
| Time | ✅ | TIME | java.sql.Time | 新しい型/サポート対象外 | 新しい型/サポート対象外 |
| Time64 | ✅ | TIME | java.sql.Time | 新しい型/サポート対象外 | 新しい型/サポート対象外 |
TimeとTime64は、新しい型として V2 でのみサポートされています。DateTimeとDateTime64は、JDBC との互換性を高めるためにjava.sql.Timestampにマッピングされます。
Enum型
| ClickHouse 型 | V1 との互換性 | JDBC 型 (V2) | Java クラス (V2) | JDBC 型 (V1) | Java クラス (V1) |
|---|---|---|---|---|---|
| Enum | ✅ | VARCHAR | java.lang.String | OTHER | java.lang.String |
| Enum8 | ✅ | VARCHAR | java.lang.String | OTHER | java.lang.String |
| Enum16 | ✅ | VARCHAR | java.lang.String | OTHER | java.lang.String |
コレクション型
| ClickHouse 型 | V1 との互換性 | JDBC 型 (V2) | Java クラス (V2) | JDBC 型 (V1) | Java クラス (V1) |
|---|---|---|---|---|---|
| Array | ❌ | ARRAY | java.sql.Array | ARRAY | Object[] またはプリミティブ型の配列 |
| Tuple | ❌ | OTHER | Object[] | STRUCT | java.sql.Struct |
| Map | ❌ | JAVA_OBJECT | java.util.Map | STRUCT | java.util.Map |
- V2 では、
Arrayは JDBC との互換性を維持するため、デフォルトでjava.sql.Arrayにマッピングされます。これは、返却される配列値に関する情報をより多く提供し、型推論に役立てるためでもあります。 - V2 では
ArrayがgetResultSet()メソッドを実装し、元の配列と同一の内容を持つjava.sql.ResultSetを返します。 - V1 は
Mapに対してSTRUCTを使用しますが、常にjava.util.Mapオブジェクトを返します。V2 では、MapをJAVA_OBJECTにマッピングすることでこの問題を解消しています。そもそもMapには名前付きカラムが存在しないため、STRUCTはMapに対して無効です。 - V1 は
Tupleに対してSTRUCTを使用しますが、常にList<Object>オブジェクトを返します。V2 ではTupleをOTHERにマッピングし、Object[]を返すことでこの問題を修正しています。これは、要素として異なる型が含まれ得るため、Listを使用するのは妥当ではないためです。 PreparedStatement#setBytesとResultSet#getBytesはコレクション型では使用できません。これらのメソッドはバイナリ文字列を扱うために設計されています。- 通常、Array 型の読み書きには
java.sql.Arrayが使われます。JDBC ドライバはこれを完全にサポートしています。
地理型
| ClickHouse 型 | V1 との互換性 | JDBC 型 (V2) | Java クラス (V2) | JDBC 型 (V1) | Java クラス (V1) |
|---|---|---|---|---|---|
| Point | ✅ | OTHER | double[] | OTHER | double[] |
| Ring | ✅ | OTHER | double[][] | OTHER | double[][] |
| Polygon | ✅ | OTHER | double[][][] | OTHER | double[][][] |
| MultiPolygon | ✅ | OTHER | double[][][][] | OTHER | double[][][][] |
Nullable型とLowCardinality型
NullableとLowCardinalityは、他の型をラップする特殊な型です。- V2 でもこれらの型には変更はありません。
特殊型
| ClickHouse 型 | V1 との互換性 | JDBC 型 (V2) | Java クラス (V2) | JDBC 型 (V1) | Java クラス (V1) |
|---|---|---|---|---|---|
| JSON | ❌ | OTHER | java.lang.String | サポートなし | サポートなし |
| AggregateFunction | ✅ | OTHER | (バイナリ表現) | OTHER | (バイナリ表現) |
| SimpleAggregateFunction | ✅ | (ラップされた型) | (ラップされたクラス) | (ラップされた型) | (ラップされたクラス) |
| UUID | ✅ | OTHER | java.util.UUID | VARCHAR | java.util.UUID |
| IPv4 | ✅ | OTHER | java.net.Inet4Address | VARCHAR | java.net.Inet4Address |
| IPv6 | ✅ | OTHER | java.net.Inet6Address | VARCHAR | java.net.Inet6Address |
| Dynamic | ❌ | OTHER | java.Object | サポートなし | サポートなし |
| Variant | ❌ | OTHER | java.Object | サポートなし | サポートなし |
- V1 は
UUIDに対してVARCHARを使用しますが、常にjava.util.UUIDオブジェクトを返します。V2 では、UUIDをOTHERにマッピングすることでこの問題を解消し、java.util.UUIDオブジェクトを返します。 - V1 では
IPv4とIPv6に対してVARCHARを使用しますが、戻り値は常にjava.net.Inet4Addressおよびjava.net.Inet6Addressオブジェクトです。V2 では、IPv4とIPv6をOTHERにマッピングすることでこの問題を解消し、java.net.Inet4Addressおよびjava.net.Inet6Addressオブジェクトを返します。 DynamicとVariantは V2 で導入された新しい型です。V1 ではサポートされていません。JSONはDynamic型に基づくため、V2 でのみサポートされています。- IPv4およびIPv6の値は、
getBytes(columnIndex)メソッドを使用してbyte[]として読み取ることもできます。ただし、これらの型については専用クラスの使用を推奨します。 - V2 では、IP アドレスを数値として読み取ることはサポートされていません。これは、その変換は
InetAddressクラスによる実装の方が適切と判断されているためです。
データベースメタデータの変更
- V2 ではデータベースの名称として
Schemaという用語のみを使用します。Catalogという用語は今後の利用のために予約されています。 - V2 は
DatabaseMetaData.supportsTransactions()およびDatabaseMetaData.supportsSavepoints()に対してfalseを返します。これは今後の開発で変更される予定です。