JDBC 드라이버
clickhouse-jdbc는 최신 Java 클라이언트를 사용하여 표준 JDBC 인터페이스를 구현합니다.
성능 또는 직접 액세스가 중요한 경우 최신 Java 클라이언트를 직접 사용하시기 바랍니다.
환경 요구 사항
- OpenJDK 버전 8 이상
설정
- Maven
- Gradle (Kotlin)
- Gradle
클래스패스에 JAR 파일을 추가해야 하는 애플리케이션에서 JDBC 드라이버를 사용하는 경우, 다음 위치에서 JAR 파일을 다운로드한 후 클래스패스에 추가하십시오:
- Maven Central에서 JAR를 다운로드한 후 클래스패스에 추가하십시오
- 버전
0.9.4부터는 https://mvnrepository.com/artifact/com.clickhouse/clickhouse-jdbc-all 아티팩트가 제공됩니다. - 모든 shaded 의존성이 포함된 JAR 파일을 받으려면 qualifier를
all로 지정하십시오.
- 버전
- 또는 공식 저장소의 릴리스 페이지에서 다운로드할 수 있습니다
구성
드라이버 클래스: com.clickhouse.jdbc.ClickHouseDriver
com.clickhouse.jdbc.ClickHouseDriver는 새로운 JDBC 구현과 이전 JDBC 구현을 위한 파사드 역할을 하는 클래스입니다. 기본적으로 새로운 JDBC 구현을 사용합니다.
이전 JDBC 구현을 사용하려면 clickhouse.jdbc.v1 시스템 속성을 true로 설정해야 합니다. 이 속성은 Driver 클래스를 호출하기 전에 설정해야 합니다.
버전을 전환하는 또 다른 방법은 각 버전의 Driver 클래스를 직접 사용하는 것입니다:
com.clickhouse.jdbc.Driver는 새로운 JDBC 구현(V2)입니다.com.clickhouse.jdbc.DriverV1은 기존 JDBC 구현(V1)입니다.
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에는 엔드포인트를 하나만 지정할 수 있습니다
- 프로토콜이 기본값인 'HTTP'가 아닌 경우에는 반드시 프로토콜을 명시해야 합니다
- 기본 포트 8123이 아닌 경우 포트를 명시해야 합니다.
- 드라이버는 포트 번호만 보고 프로토콜을 추론하지 않으므로 반드시 프로토콜을 명시적으로 지정해야 합니다
- 프로토콜을 지정하면
ssl매개변수를 설정할 필요가 없습니다.
연결 속성(Connection Properties)
주요 구성 매개변수는 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를 사용하여 쿼리 결과로 반환되는 행 수를 제한할 수 있도록 합니다. 활성화되면 사용자가 설정한 overflow 모드를 무시합니다. 자세한 내용은 JavaDoc을 참조하십시오. |
jdbc_sql_parser | JAVACC | 사용할 SQL 파서를 설정합니다. 선택 가능한 값은 ANTLR4, ANTLR4_PARAMS_PARSER, JAVACC입니다. |
remember_last_set_roles | true | 연결에 대해 마지막으로 설정된 역할을 기억합니다 |
구성 예시:
다음 JDBC URL과 동일합니다:
참고: JDBC URL이나 속성을 URL로 인코딩할 필요가 없습니다. 자동으로 인코딩됩니다.
클라이언트 식별
요청을 발생시킨 애플리케이션을 식별하는 방법은 두 가지가 있습니다: 연결 속성을 통해 com.clickhouse.client.api.ClientConfigProperties#CLIENT_NAME을 설정하거나 java.sql.Connection#setClientInfo(String name, String value) 메서드를 사용합니다.
두 방법 모두 쿼리 로그에 다음과 같은 http_user_agent 값이 기록됩니다:
작업 식별
JDBC 드라이버는 각 작업마다 query_id를 생성하며, 현재 이 값은 서버 예외에 포함됩니다.
작업의 log_comment 값을 설정하려면 com.clickhouse.jdbc.StatementImpl#getLocalSettings 메서드를 사용하십시오. 이를 위해서는
Statement 또는 PreparedStatement를 먼저 com.clickhouse.jdbc.StatementImpl로 캐스팅해야 합니다.
참고: localSettings는 스레드 간에 공유되므로 이 방식은 단일 스레드에서 statement를 사용하는 경우에만 적합합니다.
지원되는 데이터 유형
JDBC Driver는 기반 java client와 동일한 데이터 형식을 지원합니다.
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타입으로 변환하려고 시도합니다. 일부 변환에는 제한 사항이 있습니다. 자세한 내용은 각 섹션을 참조하십시오.
숫자형 타입(Numeric Types)
| 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으로도 읽을 수 있습니다. - Java
Float.MAX_VALUE를Float로 저장하면 문제가 있습니다(https://github.com/ClickHouse/clickhouse-java/issues/809). 같은 값을Double로 저장하면 해당 문제가 해결됩니다.
문자열 타입(String Types)
| 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에서 문자열 값 또는 숫자 값으로 설정할 수 있습니다.
날짜/시간 타입(Date/Time Types)
| 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>)메서드를 사용하여 두 번째 인자로 해당하는 클래스를 전달하면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으로 가져올 수 있습니다.
중첩 타입(Nested Types)
| ClickHouse 타입 | JDBC 타입 | Java 클래스 |
|---|---|---|
| Array | ARRAY | java.sql.Array |
| Tuple | OTHER | com.clickhouse.data.Tuple |
| Map | JAVA_OBJECT | java.util.Map |
| Nested | ARRAY | java.sql.Array |
Array는 JDBC와의 호환성을 위해 기본적으로java.sql.Array에 매핑됩니다. 이렇게 하면 반환되는 배열 값에 대한 정보를 더 자세히 제공할 수 있어 타입 추론에 유용합니다.Array는 원본 배열과 동일한 내용을 담은java.sql.ResultSet을 반환하는getResultSet()메서드를 구현합니다.- 컬렉션 타입은 데이터를 올바르게 표현하는 방식이 아니므로
java.lang.String으로 읽어서는 안 됩니다(예: 배열에서는 문자열 값이 따옴표로 둘러싸여 있지 않습니다). Map타입은 값을getObject(columnIndex, Class<T>)메서드를 통해서만 읽을 수 있기 때문에JAVA_OBJECT에 매핑됩니다.Map에는 이름이 붙은 컬럼이 없으므로java.sql.Struct가 아닙니다.
Tuple은 서로 다른 타입을 포함할 수 있으므로Object[]에 매핑되며,List를 사용하는 것은 지원되지 않습니다.Tuple은getObject(columnIndex, Array.class)메서드를 사용하여Array로 읽을 수 있습니다. 이 경우Array#baseTypeName은Tuple컬럼 정의를 반환합니다.
배열 쓰기
java.sql.Connection#createArrayOf를 사용하여 java.sql.Array 객체를 생성합니다. 이 객체는 서로 다른 데이터베이스에서 배열 처리를 일관되게 수행할 수 있도록 설계되었습니다.
Array 팩토리 메서드에 설정을 전달하려면 Connection이 필요합니다.
이 메서드는 두 개의 인수를 받습니다:
typeName- 배열 요소 타입의 이름입니다. 예를 들어Array(Int32)->"Int32"입니다.elements- 배열의 실제 요소입니다. 예를 들어[[1, 2, 3], [4, 5, 6]]->new Integer[][] {{1, 2, 3}, {4, 5, 6}}.
Tuple은 Object[] 또는 java.sql.Struct로 표현할 수 있습니다(튜플 작성 방법은 아래를 참조하십시오).
예제
배열 읽기
Array 객체를 읽으려면 ResultSet#getArray(columnIndex)를 사용합니다. 이 객체를 사용하면 임의의 중첩 깊이를 가진 배열에도 접근할 수 있습니다.
Array#getResultSet() 메서드는 배열 요소를 java.sql.ResultSet과 유사한 보다 일관된 방식으로 읽을 때 사용할 수 있습니다. 배열 요소의 정확한 타입을 알지 못할 때 유용합니다.
예제
튜플 쓰기
튜플은 com.clickhouse.data.Tuple 객체에 매핑되며 setObject(columnIndex, tuple) 메서드를 호출하여 이 객체로 작성해야 합니다.
이식성을 높이기 위해 java.sql.Struct 객체를 사용하여 튜플을 작성할 수도 있습니다.
예제
튜플 읽기
getObject(columnIndex) 메서드는 Object[]를 반환합니다. Tuple은 getObject(columnIndex, Array.class) 메서드를 사용하면 java.sql.Array로 읽을 수 있습니다.
예제
맵 쓰기
맵은 key-value 쌍을 필요로 하는 타입이므로 java.collections.Map 객체로만 쓸 수 있습니다. java.sql.Struct는 key-value 쌍을 지원하지 않습니다.
예제
맵 읽기
맵은 getObject(columnIndex, Map.class) 메서드를 사용하여 java.collections.Map 객체로 읽을 수 있습니다.
예제
중첩 데이터 쓰기
java.sql.Connection#createStruct를 사용하여 java.sql.Struct 객체를 인스턴스화하십시오. 이 객체는 서로 다른 데이터베이스에서 중첩 처리를 통일하기 위해 설계되었습니다.
Struct 팩토리 메서드에 구성을 전달하려면 Connection이 필요합니다.
이 메서드는 두 개의 인수를 받습니다:
typeName- 중첩 요소의 타입 이름입니다. 예를 들어Nested(Tuple(Int32, String))->"Nested(Tuple(Int32, String))"입니다.elements- 실제 중첩된 요소입니다. 예를 들어[1, 'test']->new Object[] {1, 'test'}입니다.
예제
중첩 데이터 읽기
Nested 객체를 읽기 위해서는 ResultSet#getStruct(columnIndex, StructDescriptor)를 사용합니다. 이 객체를 사용하면 중첩 수준에 상관없이 임의의 깊이의 중첩 구조에 접근할 수 있습니다.
Struct#getResultSet() 메서드는 java.sql.ResultSet과 유사한 보다 일관된 방식으로 중첩 요소를 읽는 데 사용할 수 있습니다. 중첩 요소의 정확한 타입을 알 수 없을 때 유용합니다.
예제
지리 타입(Geo Types)
| 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를 반환합니다.getObject(columnIndex, String.class)메서드를 사용하면UUID를String형식으로 읽고 쓸 수 있습니다.IPv4와IPv6는 JDBC 표준 타입이 아니지만 JDK에는 포함되어 있습니다. 기본적으로getObject()메서드에서java.net.Inet4Address와java.net.Inet6Address가 반환됩니다.IPv4및IPv6는getObject(columnIndex, String.class)메서드를 사용하면String형식으로 읽고 쓸 수 있습니다.
날짜, 시간 및 시간대 처리하기
Date/Time 및 Timestamp를 처리할 때 자주 발생하는 문제와 드라이버의 동작 로직을 설명하는 Date/Time 가이드를 참조하십시오.
연결 생성하기
자격 증명 및 설정 제공
단순 문(Simple Statement)
삽입
HikariCP
추가 정보
자세한 내용은 GitHub 저장소와 Java 클라이언트 문서를 참조하세요.
문제 해결
로깅
드라이버는 로깅을 위해 slf4j를 사용하며, classpath에서 사용 가능한 첫 번째 구현체를 사용합니다.
대용량 삽입 시 JDBC 타임아웃 해결하기
ClickHouse에서 실행 시간이 긴 대용량 삽입 작업을 수행하는 경우 다음과 같은 JDBC 타임아웃 오류가 발생할 수 있습니다:
이러한 오류는 데이터 삽입 작업을 방해하고 시스템 안정성에 영향을 줄 수 있습니다. 이 문제를 해결하려면 클라이언트 OS의 타임아웃 설정 몇 가지를 조정해야 할 수도 있습니다.
Mac OS
Mac OS에서 다음 설정을 조정하여 문제를 해결할 수 있습니다:
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에서 소켓 keep-alive 설정을 처리하는 방식이 다르기 때문에 추가 단계가 필요합니다. 다음 단계를 수행하세요:
/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(Multi-Statement SQL) | 지원되지 않음 | 허용되지 않음 |
| 명명된 매개변수 | 지원됨 | 지원되지 않음(JDBC 사양에 없음) |
PreparedStatement를 통한 데이터 스트리밍 | 지원됨 | 지원되지 않음 |
- JDBC V2는 보다 경량화되도록 구현되었으며, 그 과정에서 일부 기능이 제거되었습니다.
- 스트리밍 데이터 기능은 JDBC 사양과 Java 표준의 일부가 아니기 때문에 JDBC V2에서는 지원되지 않습니다.
- JDBC V2는 명시적인 구성 설정이 필요하며, 장애 조치(failover)를 위한 기본값은 제공되지 않습니다.
- URL에서 프로토콜을 명시해야 합니다. 포트 번호에 따른 암시적 프로토콜 감지는 지원하지 않습니다.
구성 변경 사항
열거형(enum)은 두 개만 있습니다:
com.clickhouse.jdbc.DriverProperties- 드라이버 고유의 구성 속성입니다.com.clickhouse.client.api.ClientConfigProperties- 클라이언트 구성 속성입니다. 클라이언트 구성 변경 사항은 Java 클라이언트 문서에 설명되어 있습니다.
연결 속성은 다음과 같이 파싱됩니다:
- 먼저 URL에서 속성을 파싱합니다. 이렇게 파싱된 속성은 다른 모든 속성 설정보다 우선 적용됩니다.
- 드라이버 속성은 클라이언트에 전달되지 않습니다.
- 엔드포인트(호스트, 포트, 프로토콜)는 URL에서 추출됩니다.
Example:
데이터 유형 변경 사항
숫자형 타입(Numeric Types)
| 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 타입에 매핑된다는 점입니다.
문자열 타입(String Types)
| 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으로 처리됩니다.- 문자열은 UTF-8 인코딩으로 저장됩니다.
날짜/시간 타입(Date/Time Types)
| ClickHouse 타입 | V1과 호환 여부 | 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 |
중첩 타입(Nested Types)
| 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 |
| Nested | ❌ | ARRAY | java.sql.Array | STRUCT | java.sql.Struct |
- In V2에서는 JDBC와의 호환성을 위해
Array가 기본적으로java.sql.Array에 매핑됩니다. 이는 반환되는 배열 값에 대한 정보를 더 자세히 제공하기 위한 것으로, 타입 추론에 유용합니다. - V2에서는
Array가getResultSet()메서드를 구현하여 원본 배열과 동일한 내용을 가진java.sql.ResultSet을 반환합니다. - V1은
Map에 대해STRUCT를 사용하지만 항상java.util.Map객체를 반환합니다. V2에서는Map을JAVA_OBJECT에 매핑하여 이 문제를 해결합니다. - V1은
Tuple에 대해STRUCT를 사용하지만 항상List<Object>객체를 반환합니다. V2는Tuple을OTHER에 매핑하여 기본적으로Object[]를 반환합니다. - V2에서는 튜플을 쓰기 위해
com.clickhouse.data.Tuple#Tuple을 도입합니다. 이를 통해 값이 튜플인지 배열인지 여부를 더 쉽게 판별할 수 있습니다. PreparedStatement#setBytes및ResultSet#getBytes는 컬렉션 타입에는 사용할 수 없습니다. 이 메서드는 바이너리 문자열을 처리하도록 설계되었습니다.- 일반적으로 Array 타입을 읽고 쓸 때에는
java.sql.Array를 사용합니다. JDBC 드라이버에서 이에 대한 지원을 완비하고 있습니다. - V2에서
Nested는Array에 매핑되며 튜플 배열 형태로 표현됩니다. - V2에서는
java.sql.Struct가 Array 타입과 매우 유사하고 key-value 쌍을 지원하지 않기 때문에 부분적으로만 지원합니다.Struct는Tuple값을 쓰는 데 사용할 수 있습니다.
지리 타입(Geo Types)
| 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[][][][] |
널 허용 및 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타입에 대해 JDBC 타입으로VARCHAR를 사용하지만 항상java.util.UUID객체를 반환합니다. V2에서는 이를 수정하여UUID를OTHER에 매핑하고java.util.UUID객체를 반환합니다. - V1에서는
IPv4및IPv6에 대해 JDBC 타입으로VARCHAR를 사용하지만, 항상java.net.Inet4Address및java.net.Inet6Address객체를 반환합니다. V2에서는 이를 수정하여IPv4및IPv6을 JDBC 타입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를 반환합니다. 이는 향후 개발에서 변경될 예정입니다.