본문으로 바로가기
본문으로 바로가기

Java 클라이언트

프로토콜을 통해 데이터베이스 서버와 통신하는 Java 클라이언트 라이브러리입니다. 현재 구현은 HTTP 인터페이스만 지원합니다. 이 라이브러리는 서버에 요청을 전송하기 위한 자체 API를 제공합니다. 또한 다양한 바이너리 데이터 형식(RowBinary* 및 Native*)을 처리할 수 있는 도구도 제공합니다.

설정


<dependency>
    <groupId>com.clickhouse</groupId>
    <artifactId>client-v2</artifactId>
    <version>0.9.7</version>
</dependency>

초기화

Client 객체는 com.clickhouse.client.api.Client.Builder#build()에 의해 초기화됩니다. 각 클라이언트는 고유한 컨텍스트를 가지며 객체는 클라이언트 간에 공유되지 않습니다. Builder는 편리한 설정을 위한 구성 메서드를 제공합니다.

예시:

 Client client = new Client.Builder()
                .addEndpoint("https://clickhouse-cloud-instance:8443/")
                .setUsername(user)
                .setPassword(password)
                .build();

ClientAutoCloseable이며 더 이상 필요하지 않을 때에는 닫아야 합니다.

인증

인증은 초기화 단계에서 클라이언트별로 구성됩니다. 지원되는 인증 방법은 세 가지입니다: 비밀번호, 액세스 토큰, SSL 클라이언트 인증서.

비밀번호 기반 인증을 사용하려면 setUsername(String)setPassword(String)을 호출하여 사용자 이름과 비밀번호를 설정해야 합니다:

 Client client = new Client.Builder()
        .addEndpoint("https://clickhouse-cloud-instance:8443/")
        .setUsername(user)
        .setPassword(password)
        .build();

액세스 토큰 인증을 사용하려면 setAccessToken(String)을 호출하여 액세스 토큰을 설정해야 합니다:

 Client client = new Client.Builder()
        .addEndpoint("https://clickhouse-cloud-instance:8443/")
        .setAccessToken(userAccessToken)
        .build();

SSL 클라이언트 인증서를 통한 인증을 사용하려면 setUsername(String), useSSLAuthentication(boolean), setClientCertificate(String), setClientKey(String) 메서드를 호출해 사용자 이름을 설정하고 SSL 인증을 활성화하며, 클라이언트 인증서와 클라이언트 키를 설정해야 합니다:

Client client = new Client.Builder()
        .useSSLAuthentication(true)
        .setUsername("some_user")
        .setClientCertificate("some_user.crt")
        .setClientKey("some_user.key")
참고

SSL 인증은 프로덕션 환경에서 문제 해결이 어려울 수 있습니다. 이는 SSL 라이브러리에서 발생하는 많은 오류가 충분한 정보를 제공하지 않기 때문입니다. 예를 들어, 클라이언트 인증서와 키가 일치하지 않으면 서버가 즉시 연결을 종료합니다(HTTP의 경우 HTTP 요청이 전송되기 전에 이루어지는 연결 초기화 단계에서 연결이 종료되므로 서버에서 어떤 응답도 보내지 않습니다).

인증서와 키를 검증하려면 openssl과 같은 도구를 사용하십시오:

  • 키 무결성 확인: openssl rsa -in [key-file.key] -check -noout
  • 클라이언트 인증서의 CN이 사용자와 일치하는지 확인하십시오:
    • 사용자 인증서에서 CN을 가져옵니다 - openssl x509 -noout -subject -in [user.cert]
    • 데이터베이스에 동일한 값이 설정되어 있는지 확인합니다: select name, auth_type, auth_params from system.users where auth_type = 'ssl_certificate' (쿼리는 auth_params {"common_names":["some_user"]}와 같은 형태로 출력합니다)

구성

모든 설정은 인스턴스 메서드(구성 메서드)로 정의되며, 각 값이 적용되는 범위와 컨텍스트를 명확히 합니다. 주요 구성 매개변수는 하나의 범위(클라이언트 또는 작업)에서 정의되며, 서로를 덮어쓰지 않습니다.

구성은 클라이언트 생성 시 정의됩니다. com.clickhouse.client.api.Client.Builder를 참조하세요.

클라이언트 구성

MethodArgumentsDescriptionDefaultKey
addEndpoint(String endpoint)endpoint - URL 형식의 서버 주소사용 가능한 서버 목록에 서버 엔드포인트를 추가합니다. 현재는 하나의 엔드포인트만 지원됩니다.nonenone
addEndpoint(Protocol protocol, String host, int port, boolean secure)protocol - 연결 프로토콜
host - IP 또는 호스트 이름
secure - HTTPS 사용
사용 가능한 서버 목록에 서버 엔드포인트를 추가합니다. 현재는 하나의 엔드포인트만 지원됩니다.nonenone
enableConnectionPool(boolean enable)enable - 활성/비활성 플래그커넥션 풀 사용 여부를 설정합니다.trueconnection_pool_enabled
setMaxConnections(int maxConnections)maxConnections - 커넥션 개수클라이언트가 각 서버 엔드포인트에 대해 열 수 있는 최대 커넥션 수를 설정합니다.10max_open_connections
setConnectionTTL(long timeout, ChronoUnit unit)timeout - 타임아웃 값
unit - 시간 단위
지정된 시간 이후 연결을 비활성 상태로 간주할 TTL을 설정합니다.-1connection_ttl
setKeepAliveTimeout(long timeout, ChronoUnit unit)timeout - 타임아웃 값
unit - 시간 단위
HTTP 커넥션 Keep-Alive 타임아웃을 설정합니다. Keep-Alive를 비활성화하려면 0으로 설정합니다.-http_keep_alive_timeout
setConnectionReuseStrategy(ConnectionReuseStrategy strategy)strategy - LIFO 또는 FIFO커넥션 풀에서 사용할 커넥션 재사용 전략을 선택합니다.FIFOconnection_reuse_strategy
setDefaultDatabase(String database)database - 데이터베이스 이름기본 데이터베이스를 설정합니다.defaultdatabase

클라이언트 식별

쿼리 로그에는 요청을 보낸 애플리케이션을 식별하는 두 가지 필드가 있습니다: client_namehttp_user_agent입니다. 네이티브 TCP 프로토콜은 애플리케이션을 식별하기 위해 client_name을 사용하고, HTTP 프로토콜은 http_user_agent를 사용합니다. 클라이언트 빌더에는 두 프로토콜 모두에 대해 올바른 값을 설정하는 setClientName 메서드가 있습니다. http_user_agent 필드는 User-Agent 헤더의 공통 형식에 따라 설정됩니다: application-name[/version] [(operating-system; architecture; ...)]. 이 값들의 집합은 각 계층(애플리케이션, 클라이언트 라이브러리, HTTP 클라이언트 라이브러리)마다 반복됩니다. setClientName 메서드로 설정한 값이 목록에서 가장 먼저 나타납니다.

예를 들어:

client.setClientName("my-app-01/1.0");

다음과 같은 http_user_agent 값이 설정됩니다:

my-app-01/1.0 clickhouse-java-v2/0.9.6-SNAPSHOT (Linux; jvm:17.0.17) Apache-HttpClient/5.4.4

애플리케이션은 자신을 식별하기 위해 HTTP 헤더 User-Agent를 직접 설정할 수 있습니다. 단, clickhouse-java-v2/0.9.6-SNAPSHOT 부분이 헤더 끝에 자동으로 추가됩니다.

작업 식별

쿼리 로그에는 작업을 식별하고 쿼리 로그에 추가 정보를 기록하는 데 사용할 수 있는 query_idlog_comment라는 두 개의 필드가 추가로 있습니다.

query_id는 작업의 고유 식별자입니다. 애플리케이션에서 QuerySettings 클래스의 setQueryId 메서드를 호출하여 설정할 수 있습니다.

QuerySettings querySettings = new QuerySettings();
querySettings.setQueryId("some-query-id");

log_comment은 쿼리 로그에 추가할 수 있는 주석입니다. 애플리케이션에서 QuerySettings 클래스의 logComment 메서드를 호출하여 설정할 수 있습니다.

QuerySettings querySettings = new QuerySettings();
querySettings.logComment("some-comment");

서버 설정

서버 측 설정은 클라이언트 생성 시 한 번 클라이언트 수준에서 설정할 수 있으며(BuilderserverSetting 메서드 참조), 작업 수준에서도 설정할 수 있습니다(작업 설정 클래스의 serverSetting 메서드 참조).

 try (Client client = new Client.Builder().addEndpoint(Protocol.HTTP, "localhost", mockServer.port(), false)
        .setUsername("default")
        .setPassword(ClickHouseServerForTest.getPassword())
        .compressClientRequest(true)

        // Client level
        .serverSetting("max_threads", "10")
        .serverSetting("async_insert", "1")
        .serverSetting("roles", Arrays.asList("role1", "role2"))

        .build()) {

	// Operation level
	QuerySettings querySettings = new QuerySettings();
	querySettings.serverSetting("session_timezone", "Europe/Zurich");

	...
}

⚠️ setOption 메서드(Client.Builder 또는 작업 설정 클래스)를 통해 옵션을 설정하는 경우, 서버 설정 이름 앞에 clickhouse_setting_ 접두사를 붙여야 합니다. 이때 com.clickhouse.client.api.ClientConfigProperties#serverSetting() 메서드를 사용하면 편리합니다.

커스텀 HTTP 헤더

커스텀 HTTP 헤더는 모든 작업(클라이언트 수준)에 대해 또는 단일 작업(작업 수준)에 대해 설정할 수 있습니다.


QuerySettings settings = new QuerySettings()
    .httpHeader(HttpHeaders.REFERER, clientReferer)
    .setQueryId(qId);

setOption 메서드(Client.Builder 또는 작업 설정 클래스)를 통해 옵션을 설정하는 경우 사용자 정의 헤더 이름에는 http_header_접두사를 붙여야 합니다. 이 경우com.clickhouse.client.api.ClientConfigProperties#httpHeader()` 메서드가 유용할 수 있습니다.

공통 정의

ClickHouseFormat

지원되는 형식을 나타내는 열거형(Enum)입니다. ClickHouse가 지원하는 모든 형식을 포함합니다.

  • raw - 원시 데이터는 사용자가 직접 트랜스코딩해야 합니다
  • full - 클라이언트가 데이터를 자체적으로 트랜스코딩할 수 있으며, 원시 데이터 스트림을 그대로 받아들입니다
  • - - 이 형식에서는 ClickHouse가 해당 연산을 지원하지 않습니다

이 클라이언트 버전에서 지원하는 형식은 다음과 같습니다:

형식입력출력
TabSeparated원시원시
TabSeparatedRaw원시원시
TabSeparatedWithNames원시원시
TabSeparatedWithNamesAndTypes원시원시
TabSeparatedRawWithNames원시원시
TabSeparatedRawWithNamesAndTypes원시원시
Template원시원시
TemplateIgnoreSpaces원시*
CSV원시원시
CSVWithNames원시원시
CSVWithNamesAndTypes원시원시
CustomSeparated원시원시
CustomSeparatedWithNames원시원시
CustomSeparatedWithNamesAndTypes원시원시
SQLInsert-원시
Values원시원시
Vertical*원시
JSON원시원시
JSONAsString원시-
JSONAsObject원시*
JSONStrings원시원시
JSONColumns원시원시
JSONColumnsWithMetadata원시원시
JSONCompact원시원시
JSONCompactStrings-원시
JSONCompactColumns원시raw
JSONEachRowrawraw
PrettyJSONEachRow*raw
JSONEachRowWithProgress-raw
JSONStringsEachRowrawraw
JSONStringsEachRowWithProgress*raw
JSONCompactEachRowrawraw
JSONCompactEachRowWithNamesrawraw
JSONCompactEachRowWithNamesAndTypesrawraw
JSONCompactStringsEachRowrawraw
JSONCompactStringsEachRowWithNamesrawraw
JSONCompactStringsEachRowWithNamesAndTypesrawraw
JSONObjectEachRowrawraw
BSONEachRowrawraw
TSKV원시 형식원시 형식
Pretty-원시 형식
PrettyNoEscapes*원시 형식
PrettyMonoBlock-원시 형식
PrettyNoEscapesMonoBlock*원시 형식
PrettyCompact-원시 형식
PrettyCompactNoEscapes*원시 형식
PrettyCompactMonoBlock-원시 형식
PrettyCompactNoEscapesMonoBlock*원시 형식
PrettySpace-원시 형식
PrettySpaceNoEscapes*원시 형식
PrettySpaceMonoBlock-원시 형식
PrettySpaceNoEscapesMonoBlock*원시 형식
Prometheus-원시
Protobuf원시원시
ProtobufSingle원시원시
ProtobufList원시원시
Avro원시원시
AvroConfluent원시*
Parquet원시원시
ParquetMetadata원시-
Arrow원시원시
ArrowStream원시원시
ORC원시원시
One원시*
Npy원시원시
RowBinary전체전체
RowBinaryWithNames전체전체
RowBinaryWithNamesAndTypes전체전체
RowBinaryWithDefaults전체-
Native전체원시
Null*원시
XML-원시
CapnProto원시원시
LineAsString원시원시
Regexp원시*
RawBLOB원시원시
MsgPack원시원시
MySQLDump원시-
DWARF원시*
Markdown-원시
양식원시*

Insert API

insert(String tableName, InputStream data, ClickHouseFormat format)

지정된 형식으로 인코딩된 바이트를 담은 InputStream으로 데이터를 입력받습니다. data는 지정된 format으로 인코딩되어 있어야 합니다.

시그니처

CompletableFuture<InsertResponse> insert(String tableName, InputStream data, ClickHouseFormat format, InsertSettings settings)
CompletableFuture<InsertResponse> insert(String tableName, InputStream data, ClickHouseFormat format)

매개변수

tableName - 대상 테이블 이름.

data - 인코딩된 데이터가 담긴 입력 스트림입니다.

format - 데이터가 인코딩된 형식입니다.

settings - 요청 설정입니다.

반환값

InsertResponse 타입의 Future로, 작업 결과와 서버 측 메트릭과 같은 추가 정보를 반환합니다.

예제

try (InputStream dataStream = getDataStream()) {
    try (InsertResponse response = client.insert(TABLE_NAME, dataStream, ClickHouseFormat.JSONEachRow,
            insertSettings).get(3, TimeUnit.SECONDS)) {

        log.info("Insert finished: {} rows written", response.getMetrics().getMetric(ServerMetrics.NUM_ROWS_WRITTEN).getLong());
    } catch (Exception e) {
        log.error("Failed to write JSONEachRow data", e);
        throw new RuntimeException(e);
    }
}

insert(String tableName, List<?> data, InsertSettings settings)

데이터베이스에 쓰기 요청을 보냅니다. 객체 목록은 효율적인 형식으로 변환된 후 서버로 전송됩니다. 목록 항목의 클래스는 register(Class, TableSchema) 메서드를 사용해 미리 등록해야 합니다.

시그니처

client.insert(String tableName, List<?> data, InsertSettings settings)
client.insert(String tableName, List<?> data)

파라미터

tableName - 대상 테이블의 이름입니다.

data - DTO(Data Transfer Object) 객체 컬렉션입니다.

settings - 요청 설정입니다.

반환값

InsertResponse 타입의 Future — 작업 결과와 서버 측 메트릭과 같은 추가 정보를 포함합니다.

예시

// Important step (done once) - register class to pre-compile object serializer according to the table schema.
client.register(ArticleViewEvent.class, client.getTableSchema(TABLE_NAME));

List<ArticleViewEvent> events = loadBatch();

try (InsertResponse response = client.insert(TABLE_NAME, events).get()) {
    // handle response, then it will be closed and connection that served request will be released.
}

InsertSettings

삽입 작업에 대한 구성 옵션입니다.

구성 방법

메서드설명
setQueryId(String queryId)작업에 할당될 쿼리 ID를 설정합니다. 기본값은 null입니다.
setDeduplicationToken(String token)중복 제거 토큰을 설정합니다. 이 토큰은 서버로 전송되어 쿼리를 식별하는 데 사용할 수 있습니다. 기본값은 null입니다.
setInputStreamCopyBufferSize(int size)복사용 버퍼 크기입니다. 이 버퍼는 쓰기 작업 동안 사용자 제공 입력 스트림에서 출력 스트림으로 데이터를 복사하는 데 사용됩니다. 기본값: 8196.
serverSetting(String name, String value)개별 작업에 대한 서버 설정을 지정합니다.
serverSetting(String name, Collection values)단일 작업에 대해 여러 값을 사용하는 개별 서버 설정을 지정합니다. 컬렉션의 각 항목은 String 값이어야 합니다.
setDBRoles(Collection dbRoles)작업을 실행하기 전에 적용할 DB 역할을 설정합니다. 컬렉션의 항목은 String 값이어야 합니다.
setOption(String option, Object value)원시(raw) 형식으로 구성 옵션을 설정합니다. 서버 설정은 아닙니다.

InsertResponse

삽입 작업 결과를 담는 응답 객체입니다. 클라이언트가 서버로부터 응답을 받은 경우에만 사용할 수 있습니다.

참고

이전 응답의 모든 데이터를 끝까지 읽기 전에는 이 연결을 재사용할 수 없으므로, 연결을 해제하려면 이 객체를 가능한 한 빨리 닫아야 합니다.

메서드설명
OperationMetrics getMetrics()작업 메트릭 객체를 반환합니다.
String getQueryId()애플리케이션이(작업 설정 또는 서버를 통해) 작업에 할당한 쿼리 ID를 반환합니다.

쿼리 API

query(String sqlQuery)

sqlQuery를 있는 그대로 전송합니다. 응답 형식은 쿼리 설정에 의해 지정됩니다. QueryResponse는 해당 형식을 지원하는 리더가 소비해야 하는 응답 스트림에 대한 참조를 유지합니다.

시그니처

CompletableFuture<QueryResponse> query(String sqlQuery, QuerySettings settings)
CompletableFuture<QueryResponse> query(String sqlQuery)

파라미터

sqlQuery - 단일 SQL 문입니다. 쿼리는 있는 그대로 서버로 전송됩니다.

settings - 요청 설정입니다.

반환값

QueryResponse 타입의 Future로, 결과 데이터셋과 서버 측 메트릭과 같은 추가 정보를 포함합니다. 데이터셋을 모두 읽은 후 Response 객체를 닫아야 합니다.

예시

final String sql = "select * from " + TABLE_NAME + " where title <> '' limit 10";

// Default format is RowBinaryWithNamesAndTypesFormatReader so reader have all information about columns
try (QueryResponse response = client.query(sql).get(3, TimeUnit.SECONDS);) {

    // Create a reader to access the data in a convenient way
    ClickHouseBinaryFormatReader reader = client.newBinaryFormatReader(response);

    while (reader.hasNext()) {
        reader.next(); // Read the next record from stream and parse it

        // get values
        double id = reader.getDouble("id");
        String title = reader.getString("title");
        String url = reader.getString("url");

        // collecting data
    }
} catch (Exception e) {
    log.error("Failed to read data", e);
}

// put business logic outside of the reading block to release http connection asap.

query(String sqlQuery, Map<String, Object> queryParams, QuerySettings settings)

sqlQuery를 그대로 전송합니다. 또한 서버가 SQL 표현식을 컴파일할 수 있도록 쿼리 매개변수도 함께 전송합니다.

시그니처

CompletableFuture<QueryResponse> query(String sqlQuery, Map<String, Object> queryParams, QuerySettings settings)

매개변수

sqlQuery - {} 플레이스홀더를 포함하는 SQL 표현식입니다.

queryParams - 서버 측에서 SQL 표현식을 완성하는 데 사용하는 변수 맵입니다.

settings - 요청 설정입니다.

반환값

QueryResponse 타입의 Future로, 결과 데이터셋과 서버 측 메트릭과 같은 추가 정보를 포함합니다. 데이터셋을 모두 소비한 후 Response 객체를 닫아야 합니다.

예시


// define parameters. They will be sent to the server along with the request.
Map<String, Object> queryParams = new HashMap<>();
queryParams.put("param1", 2);

try (QueryResponse response =
        client.query("SELECT * FROM " + table + " WHERE col1 >= {param1:UInt32}", queryParams, new QuerySettings()).get()) {

    // Create a reader to access the data in a convenient way
    ClickHouseBinaryFormatReader reader = client.newBinaryFormatReader(response);

    while (reader.hasNext()) {
        reader.next(); // Read the next record from stream and parse it

        // reading data
    }

} catch (Exception e) {
    log.error("Failed to read data", e);
}

queryAll(String sqlQuery)

RowBinaryWithNamesAndTypes 형식의 데이터를 조회합니다. 결과는 컬렉션으로 반환됩니다. 읽기 성능은 리더를 사용할 때와 동일하지만, 전체 결과 집합을 메모리에 유지해야 하므로 더 많은 메모리가 필요합니다.

시그니처

List<GenericRecord> queryAll(String sqlQuery)

매개변수

sqlQuery - 서버에서 데이터를 조회하기 위한 SQL 표현식입니다.

반환값

결과 데이터를 행 형식으로 접근할 수 있도록 하는 GenericRecord 객체들의 목록으로 표현된 전체 데이터셋입니다.

예시

try {
    log.info("Reading whole table and process record by record");
    final String sql = "select * from " + TABLE_NAME + " where title <> ''";

    // Read whole result set and process it record by record
    client.queryAll(sql).forEach(row -> {
        double id = row.getDouble("id");
        String title = row.getString("title");
        String url = row.getString("url");

        log.info("id: {}, title: {}, url: {}", id, title, url);
    });
} catch (Exception e) {
    log.error("Failed to read data", e);
}

QuerySettings

쿼리 작업에 대한 구성 옵션입니다.

구성 방법

메서드설명
setQueryId(String queryId)작업에 할당할 쿼리 ID를 설정합니다.
setFormat(ClickHouseFormat format)응답 형식을 설정합니다. 사용 가능한 전체 형식 목록은 RowBinaryWithNamesAndTypes를 참조하십시오.
setMaxExecutionTime(Integer maxExecutionTime)서버에서의 작업 최대 실행 시간을 설정합니다. 읽기 타임아웃에는 영향을 주지 않습니다.
waitEndOfQuery(Boolean waitEndOfQuery)응답을 전송하기 전에 쿼리가 끝날 때까지 대기하도록 서버에 요청합니다.
setUseServerTimeZone(Boolean useServerTimeZone)연산 결과의 날짜/시간 타입을 파싱할 때 서버 시간대(클라이언트 설정 참조)가 사용됩니다. 기본값은 false입니다.
setUseTimeZone(String timeZone)시간 변환에 timeZone을 사용하도록 서버에 요청합니다. session_timezone을(를) 참조하십시오.
serverSetting(String name, String value)작업에 대해 개별 서버 설정을 지정합니다.
serverSetting(String name, Collection values)단일 작업에서 여러 값을 갖는 개별 서버 설정을 지정합니다. 컬렉션의 각 항목은 String 값이어야 합니다.
setDBRoles(Collection dbRoles)작업 실행 전에 설정할 DB 역할을 지정합니다. 컬렉션의 항목은 String 값이어야 합니다.
setOption(String option, Object value)구성 옵션을 원시(raw) 형식으로 설정합니다. 서버 설정이 아닙니다.

QueryResponse

쿼리 실행 결과를 담고 있는 응답 객체입니다. 클라이언트가 서버로부터 응답을 받은 경우에만 사용 가능합니다.

참고

이전 응답의 모든 데이터를 완전히 읽기 전까지는 연결을 재사용할 수 없으므로, 연결을 반환하려면 이 객체를 가능한 한 빨리 닫아야 합니다.

MethodDescription
ClickHouseFormat getFormat()응답 데이터가 어떤 형식으로 인코딩되어 있는지 반환합니다.
InputStream getInputStream()지정된 형식으로 인코딩된, 압축되지 않은 데이터 바이트 스트림을 반환합니다.
OperationMetrics getMetrics()작업 메트릭을 포함하는 객체를 반환합니다.
String getQueryId()애플리케이션이 작업에 할당한 쿼리 ID를 반환합니다(작업 설정 또는 서버를 통해 설정됨).
TimeZone getTimeZone()응답의 Date/DateTime 타입을 처리할 때 사용할 시간대를 반환합니다.

예시

  • 예제 코드는 저장소에서 확인할 수 있습니다.
  • Spring 서비스 구현을 참고하십시오

공통 API

getTableSchema(String table)

table에 대한 테이블 스키마를 가져옵니다.

시그니처

TableSchema getTableSchema(String table)
TableSchema getTableSchema(String table, String database)

파라미터

table - 스키마 데이터를 조회할 테이블 이름입니다.

database - 대상 테이블이 정의된 데이터베이스.

반환값

테이블의 컬럼 목록이 포함된 TableSchema 객체를 반환합니다.

getTableSchemaFromQuery(String sql)

SQL 문에서 스키마를 가져옵니다.

시그니처

TableSchema getTableSchemaFromQuery(String sql)

파라미터

sql - 스키마를 반환하는 "SELECT" SQL 문입니다.

반환값

sql 표현식과 일치하는 컬럼들로 구성된 TableSchema 객체를 반환합니다.

TableSchema

register(Class<?> clazz, TableSchema schema)

Java 클래스가 schema를 사용하여 데이터를 쓰고 읽을 수 있도록 직렬화 및 역직렬화 레이어를 컴파일합니다. 이 메서드는 getter/setter 쌍과 해당 컬럼에 대한 직렬화기 및 역직렬화기를 생성합니다. 컬럼 매칭은 메서드 이름에서 컬럼 이름을 추출하여 수행됩니다. 예를 들어, getFirstNamefirst_name 또는 firstname 컬럼에 대응됩니다.

시그니처

void register(Class<?> clazz, TableSchema schema)

파라미터

clazz - 데이터를 읽고 쓰는 데 사용되는 POJO를 나타내는 클래스입니다.

schema - POJO 속성과 매칭하는 데 사용할 데이터 스키마입니다.

예시

client.register(ArticleViewEvent.class, client.getTableSchema(TABLE_NAME));

사용 예제

전체 예제 코드는 저장소의 'example` 폴더에 저장되어 있습니다:

  • client-v2 - 주요 예제 모음입니다.
  • demo-service - Spring Boot 애플리케이션에서 클라이언트를 사용하는 예제입니다.
  • demo-kotlin-service - Ktor(Kotlin) 애플리케이션에서 클라이언트를 사용하는 방법을 보여주는 예제입니다.

데이터 읽기

데이터를 읽는 대표적인 방법은 두 가지입니다:

  • query() 메서드는 데이터가 들어 있는 InputStream을 포함한 저수준의 QueryResponse 객체를 반환합니다. 일반적으로 스트리밍 읽기를 위해 ClickHouseBinaryFormatReader와 함께 사용되지만 다른 사용자 정의 리더 구현과 함께 사용할 수도 있습니다. QueryResponse는 결과 집합의 메타데이터와 메트릭에 대한 접근도 제공합니다.
  • queryAll() 메서드와 GenericRecord를 사용하면 행 단위로 데이터에 편리하게 접근할 수 있습니다. 이 경우 결과 집합 전체가 메모리에 로드됩니다.
  • queryRecords() 메서드는 com.clickhouse.client.api.query.Records를 반환하며, 이는 GenericRecord 객체에 대한 이터레이터입니다. 이 메서드는 데이터를 메모리에 적재하지 않는 스트리밍 방식을 사용하며, 데이터에는 GenericRecord를 통해 접근합니다.

참고: 스트리밍 방식은 데이터를 네트워크 스트림에서 직접 읽기 때문에 읽기 속도가 충분히 빠르지 않으면 서버 쓰기 타임아웃이 발생할 수 있습니다.

배열 읽기

ClickHouseBinaryFormatReader 메서드

  • getList(...) - 임의의 Array(...)List<T> 형태로 읽습니다. 유연한 타입 읽기에 적합한 기본 옵션입니다. 중첩 배열을 지원합니다.
  • getByteArray(...), getShortArray(...), getIntArray(...), getLongArray(...), getFloatArray(...), getDoubleArray(...), getBooleanArray(...) - 기본(primitive) 타입과 호환되는 값으로 이루어진 1차원 배열에 가장 적합합니다.
  • getStringArray(...) - Array(String)(및 이름으로 표현되는 enum 값)을 위한 메서드입니다.
  • getObjectArray(...) - 중첩 배열을 포함한 모든 Array(...) 요소 타입에 사용할 수 있는 범용 옵션입니다. 널 허용 값을 포함하는 배열과 중첩 배열을 읽을 때 사용합니다.

모든 메서드에는 인덱스 기반 및 이름 기반 오버로드가 제공됩니다. 인덱스는 1부터 시작합니다. 인덱스 기반 메서드는 열에 직접 접근합니다. 이름 기반 메서드는 매 호출마다 인덱스를 조회해야 합니다.

try (QueryResponse response = client.query("SELECT * FROM my_table").get()) {
    ClickHouseBinaryFormatReader reader = client.newBinaryFormatReader(response);
    while (reader.next() != null) {
        
        Object[] uint64 = reader.getObjectArray("uint64_arr"); // Array(UInt64) -> BigInteger[]
        Object[] arr2d = reader.getObjectArray("arr2d");       // Array(Array(Int64)) -> Object[]

        // nested arrays are returned as nested Object[]:
        Object[] firstInner = (Object[]) arr2d[0];
        Long firstValue = (Long) firstInner[0];
    }
}

GenericRecord 메서드

  • getList(...) - 임의의 Array(...)List<T> 형태로 읽습니다. 유연한 타입 읽기 작업에 적합한 기본 선택입니다. 중첩 배열을 지원합니다.
  • getByteArray(...), getShortArray(...), getIntArray(...), getLongArray(...), getFloatArray(...), getDoubleArray(...), getBooleanArray(...) - 원시(primitive) 타입과 호환되는 값들로 구성된 1차원 배열에 가장 적합합니다.
  • getStringArray(...) - Array(String)(및 이름으로 표현되는 enum 값)을 위한 메서드입니다.
  • getObjectArray(...) - 중첩 배열을 포함한 모든 Array(...) 요소 타입에 사용할 수 있는 일반적인 옵션입니다. 널 허용 값이나 중첩 배열을 포함하는 배열을 읽는 데 사용합니다.

모든 메서드는 인덱스 기반 및 이름 기반 오버로드를 사용할 수 있습니다. 인덱스는 1부터 시작합니다. 인덱스 기반 방식은 컬럼에 직접 접근합니다. 이름 기반 메서드는 매번 인덱스를 조회해야 합니다.

try (QueryResponse response = client.query("SELECT * FROM my_table").get()) {
    List<GenericRecord> rows = client.queryAll(
        "SELECT int_arr, arr2d_nullable FROM test_arrays ORDER BY id");

    for (GenericRecord row : rows) {
        Object[] intArr = row.getObjectArray("int_arr");                 // Array(Int32) -> Integer[]
        Object[] arr2d = row.getObjectArray("arr2d_nullable");           // Array(Array(Nullable(Int32)))

        Object[] inner = (Object[]) arr2d[0];
        Object maybeNull = inner[1]; // may be null
    }
}


## Migration Guide                   


Old client (V1) was using `com.clickhouse.client.ClickHouseClient#builder` as start point. The new client (V2) uses similar pattern with `com.clickhouse.client.api.Client.Builder`. Main
differences are:
- no service loader is used to grab implementation. The `com.clickhouse.client.api.Client` is facade class for all kinds of implementation in the future.
- a fewer sources of configuration: one is provided to the builder and one is with operation settings (`QuerySettings`, `InsertSettings`). Previous version had configuration per node and was loading
env. variables in some cases.

### Configuration Parameters Match                            

There are 3 enum classes related to configuration in V1:
- `com.clickhouse.client.config.ClickHouseDefaults` - configuration parameters that supposed to be set in most use cases. Like `USER` and `PASSWORD`.
- `com.clickhouse.client.config.ClickHouseClientOption` - configuration parameters specific for the client. Like `HEALTH_CHECK_INTERVAL`.
- `com.clickhouse.client.http.config.ClickHouseHttpOption` - configuration parameters specific for HTTP interface. Like `RECEIVE_QUERY_PROGRESS`.

They were designed to group parameters and provide clear separation. However in some cases it lead to a confusion (is there a difference between `com.clickhouse.client.config.ClickHouseDefaults#ASYNC` and
`com.clickhouse.client.config.ClickHouseClientOption#ASYNC`). The new V2 client uses `com.clickhouse.client.api.Client.Builder` as single dictionary of all possible client configuration options.There is
`com.clickhouse.client.api.ClientConfigProperties` where all configuration parameter names are listed.

Table below shows what old options are supported in the new client and their new meaning.

**Legend:** ✔ = supported, ✗ = dropped

<Tabs groupId="v1-migration">
<TabItem value="connection-auth" label="Connection & Auth">

| V1 Configuration | V2 Builder Method | Comments |
|------------------|-------------------|----------|
| `ClickHouseDefaults#HOST` | `Client.Builder#addEndpoint` | |
| `ClickHouseDefaults#PROTOCOL` | ✗ | Only HTTP supported in V2 |
| `ClickHouseDefaults#DATABASE`<br/>`ClickHouseClientOption#DATABASE` | `Client.Builder#setDefaultDatabase` | |
| `ClickHouseDefaults#USER` | `Client.Builder#setUsername` | |
| `ClickHouseDefaults#PASSWORD` | `Client.Builder#setPassword` | |
| `ClickHouseClientOption#CONNECTION_TIMEOUT` | `Client.Builder#setConnectTimeout` | |
| `ClickHouseClientOption#CONNECTION_TTL` | `Client.Builder#setConnectionTTL` | |
| `ClickHouseHttpOption#MAX_OPEN_CONNECTIONS` | `Client.Builder#setMaxConnections` | |
| `ClickHouseHttpOption#KEEP_ALIVE`<br/>`ClickHouseHttpOption#KEEP_ALIVE_TIMEOUT` | `Client.Builder#setKeepAliveTimeout` | |
| `ClickHouseHttpOption#CONNECTION_REUSE_STRATEGY` | `Client.Builder#setConnectionReuseStrategy` | |
| `ClickHouseHttpOption#USE_BASIC_AUTHENTICATION` | `Client.Builder#useHTTPBasicAuth` | |

</TabItem>

<TabItem value="ssl" label="SSL & Security">

| V1 Configuration | V2 Builder Method | Comments |
|------------------|-------------------|----------|
| `ClickHouseDefaults#SSL_CERTIFICATE_TYPE` | ✗ | |
| `ClickHouseDefaults#SSL_KEY_ALGORITHM` | ✗ | |
| `ClickHouseDefaults#SSL_PROTOCOL` | ✗ | |
| `ClickHouseClientOption#SSL` | ✗ | See `Client.Builder#addEndpoint` |
| `ClickHouseClientOption#SSL_MODE` | ✗ | |
| `ClickHouseClientOption#SSL_ROOT_CERTIFICATE` | `Client.Builder#setRootCertificate` | SSL Auth should be enabled by `useSSLAuthentication` |
| `ClickHouseClientOption#SSL_CERTIFICATE` | `Client.Builder#setClientCertificate` | |
| `ClickHouseClientOption#SSL_KEY` | `Client.Builder#setClientKey` | |
| `ClickHouseClientOption#KEY_STORE_TYPE` | `Client.Builder#setSSLTrustStoreType` | |
| `ClickHouseClientOption#TRUST_STORE` | `Client.Builder#setSSLTrustStore` | |
| `ClickHouseClientOption#KEY_STORE_PASSWORD` | `Client.Builder#setSSLTrustStorePassword` | |
| `ClickHouseClientOption#SSL_SOCKET_SNI` | `Client.Builder#sslSocketSNI` | |
| `ClickHouseClientOption#CUSTOM_SOCKET_FACTORY` | ✗ | |
| `ClickHouseClientOption#CUSTOM_SOCKET_FACTORY_OPTIONS` | ✗ | See `Client.Builder#sslSocketSNI` to set SNI |

</TabItem>

<TabItem value="socket" label="Socket Options">

| V1 Configuration | V2 Builder Method | Comments |
|------------------|-------------------|----------|
| `ClickHouseClientOption#SOCKET_TIMEOUT` | `Client.Builder#setSocketTimeout` | |
| `ClickHouseClientOption#SOCKET_REUSEADDR` | `Client.Builder#setSocketReuseAddress` | |
| `ClickHouseClientOption#SOCKET_KEEPALIVE` | `Client.Builder#setSocketKeepAlive` | |
| `ClickHouseClientOption#SOCKET_LINGER` | `Client.Builder#setSocketLinger` | |
| `ClickHouseClientOption#SOCKET_IP_TOS` | ✗ | |
| `ClickHouseClientOption#SOCKET_TCP_NODELAY` | `Client.Builder#setSocketTcpNodelay` | |
| `ClickHouseClientOption#SOCKET_RCVBUF` | `Client.Builder#setSocketRcvbuf` | |
| `ClickHouseClientOption#SOCKET_SNDBUF` | `Client.Builder#setSocketSndbuf` | |

</TabItem>

<TabItem value="compression" label="Compression">

| V1 Configuration | V2 Builder Method | Comments |
|------------------|-------------------|----------|
| `ClickHouseClientOption#COMPRESS` | `Client.Builder#compressServerResponse` | See also `useHttpCompression` |
| `ClickHouseClientOption#DECOMPRESS` | `Client.Builder#compressClientRequest` | See also `useHttpCompression` |
| `ClickHouseClientOption#COMPRESS_ALGORITHM` | ✗ | `LZ4` for non-http. Http uses `Accept-Encoding` |
| `ClickHouseClientOption#DECOMPRESS_ALGORITHM` | ✗ | `LZ4` for non-http. Http uses `Content-Encoding` |
| `ClickHouseClientOption#COMPRESS_LEVEL` | ✗ | |
| `ClickHouseClientOption#DECOMPRESS_LEVEL` | ✗ | |

</TabItem>

<TabItem value="proxy" label="Proxy">

| V1 Configuration | V2 Builder Method | Comments |
|------------------|-------------------|----------|
| `ClickHouseClientOption#PROXY_TYPE` | `Client.Builder#addProxy` | |
| `ClickHouseClientOption#PROXY_HOST` | `Client.Builder#addProxy` | |
| `ClickHouseClientOption#PROXY_PORT` | `Client.Builder#addProxy` | |
| `ClickHouseClientOption#PROXY_USERNAME` | `Client.Builder#setProxyCredentials` | |
| `ClickHouseClientOption#PROXY_PASSWORD` | `Client.Builder#setProxyCredentials` | |

</TabItem>

<TabItem value="timeouts-retry" label="Timeouts & Retry">

| V1 Configuration | V2 Builder Method | Comments |
|------------------|-------------------|----------|
| `ClickHouseClientOption#MAX_EXECUTION_TIME` | `Client.Builder#setExecutionTimeout` | |
| `ClickHouseClientOption#RETRY` | `Client.Builder#setMaxRetries` | See also `retryOnFailures` |
| `ClickHouseHttpOption#AHC_RETRY_ON_FAILURE` | `Client.Builder#retryOnFailures` | |
| `ClickHouseClientOption#FAILOVER` | ✗ | |
| `ClickHouseClientOption#REPEAT_ON_SESSION_LOCK` | ✗ | |
| `ClickHouseClientOption#SESSION_ID` | ✗ | |
| `ClickHouseClientOption#SESSION_CHECK` | ✗ | |
| `ClickHouseClientOption#SESSION_TIMEOUT` | ✗ | |

</TabItem>

<TabItem value="timezone" label="Timezone">

| V1 Configuration | V2 Builder Method | Comments |
|------------------|-------------------|----------|
| `ClickHouseDefaults#SERVER_TIME_ZONE`<br/>`ClickHouseClientOption#SERVER_TIME_ZONE` | `Client.Builder#setServerTimeZone` | |
| `ClickHouseClientOption#USE_SERVER_TIME_ZONE` | `Client.Builder#useServerTimeZone` | |
| `ClickHouseClientOption#USE_SERVER_TIME_ZONE_FOR_DATES` | | |
| `ClickHouseClientOption#USE_TIME_ZONE` | `Client.Builder#useTimeZone` | |

</TabItem>

<TabItem value="buffers" label="Buffers & Performance">

| V1 Configuration | V2 Builder Method | Comments |
|------------------|-------------------|----------|
| `ClickHouseClientOption#BUFFER_SIZE` | `Client.Builder#setClientNetworkBufferSize` | |
| `ClickHouseClientOption#BUFFER_QUEUE_VARIATION` | ✗ | |
| `ClickHouseClientOption#READ_BUFFER_SIZE` | ✗ | |
| `ClickHouseClientOption#WRITE_BUFFER_SIZE` | ✗ | |
| `ClickHouseClientOption#REQUEST_CHUNK_SIZE` | ✗ | |
| `ClickHouseClientOption#REQUEST_BUFFERING` | ✗ | |
| `ClickHouseClientOption#RESPONSE_BUFFERING` | ✗ | |
| `ClickHouseClientOption#MAX_BUFFER_SIZE` | ✗ | |
| `ClickHouseClientOption#MAX_QUEUED_BUFFERS` | ✗ | |
| `ClickHouseClientOption#MAX_QUEUED_REQUESTS` | ✗ | |
| `ClickHouseClientOption#REUSE_VALUE_WRAPPER` | ✗ | |

</TabItem>

<TabItem value="threading" label="Threading & Async">

| V1 Configuration | V2 Builder Method | Comments |
|------------------|-------------------|----------|
| `ClickHouseDefaults#ASYNC`<br/>`ClickHouseClientOption#ASYNC` | `Client.Builder#useAsyncRequests` | |
| `ClickHouseDefaults#MAX_SCHEDULER_THREADS` | ✗ | see `setSharedOperationExecutor` |
| `ClickHouseDefaults#MAX_THREADS` | ✗ | see `setSharedOperationExecutor` |
| `ClickHouseDefaults#THREAD_KEEPALIVE_TIMEOUT` | see `setSharedOperationExecutor` | |
| `ClickHouseClientOption#MAX_THREADS_PER_CLIENT` | ✗ | |
| `ClickHouseClientOption#MAX_CORE_THREAD_TTL` | ✗ | |

</TabItem>

<TabItem value="http-headers" label="HTTP & Headers">

| V1 Configuration | V2 Builder Method | Comments |
|------------------|-------------------|----------|
| `ClickHouseHttpOption#CUSTOM_HEADERS` | `Client.Builder#httpHeaders` | |
| `ClickHouseHttpOption#CUSTOM_PARAMS` | ✗ | See `Client.Builder#serverSetting` |
| `ClickHouseClientOption#CLIENT_NAME` | `Client.Builder#setClientName` | |
| `ClickHouseHttpOption#CONNECTION_PROVIDER` | ✗ | |
| `ClickHouseHttpOption#DEFAULT_RESPONSE` | ✗ | |
| `ClickHouseHttpOption#SEND_HTTP_CLIENT_ID` | ✗ | |
| `ClickHouseHttpOption#AHC_VALIDATE_AFTER_INACTIVITY` | ✗ | Always enabled when Apache Http Client is used |

</TabItem>

<TabItem value="format-query" label="Format & Query">

| V1 Configuration | V2 Builder Method | Comments |
|------------------|-------------------|----------|
| `ClickHouseDefaults#FORMAT`<br/>`ClickHouseClientOption#FORMAT` | ✗ | Moved to operation settings (`QuerySettings` and `InsertSettings`) |
| `ClickHouseClientOption#QUERY_ID` | ✗ | See `QuerySettings` and `InsertSettings` |
| `ClickHouseClientOption#LOG_LEADING_COMMENT` | ✗ | See `QuerySettings#logComment` and `InsertSettings#logComment` |
| `ClickHouseClientOption#MAX_RESULT_ROWS` | ✗ | Is server side setting |
| `ClickHouseClientOption#RESULT_OVERFLOW_MODE` | ✗ | Is server side setting |
| `ClickHouseHttpOption#RECEIVE_QUERY_PROGRESS` | ✗ | Server side setting |
| `ClickHouseHttpOption#WAIT_END_OF_QUERY` | ✗ | Server side setting |
| `ClickHouseHttpOption#REMEMBER_LAST_SET_ROLES` | `Client#setDBRoles` | Runtime config now. See also `QuerySettings#setDBRoles` and `InsertSettings#setDBRoles` |

</TabItem>

<TabItem value="node-discovery" label="Node Discovery & Load Balancing">

| V1 Configuration | V2 Builder Method | Comments |
|------------------|-------------------|----------|
| `ClickHouseClientOption#AUTO_DISCOVERY` | ✗ | |
| `ClickHouseClientOption#LOAD_BALANCING_POLICY` | ✗ | |
| `ClickHouseClientOption#LOAD_BALANCING_TAGS` | ✗ | |
| `ClickHouseClientOption#HEALTH_CHECK_INTERVAL` | ✗ | |
| `ClickHouseClientOption#HEALTH_CHECK_METHOD` | ✗ | |
| `ClickHouseClientOption#NODE_DISCOVERY_INTERVAL` | ✗ | |
| `ClickHouseClientOption#NODE_DISCOVERY_LIMIT` | ✗ | |
| `ClickHouseClientOption#NODE_CHECK_INTERVAL` | ✗ | |
| `ClickHouseClientOption#NODE_GROUP_SIZE` | ✗ | |
| `ClickHouseClientOption#CHECK_ALL_NODES` | ✗ | |

</TabItem>

<TabItem value="misc" label="Miscellaneous">

| V1 Configuration | V2 Builder Method | Comments |
|------------------|-------------------|----------|
| `ClickHouseDefaults#AUTO_SESSION` | ✗ | Session support will be reviewed |
| `ClickHouseDefaults#BUFFERING` | ✗ | |
| `ClickHouseDefaults#MAX_REQUESTS` | ✗ | |
| `ClickHouseDefaults#ROUNDING_MODE` | | |
| `ClickHouseDefaults#SERVER_VERSION`<br/>`ClickHouseClientOption#SERVER_VERSION` | `Client.Builder#setServerVersion` | |
| `ClickHouseDefaults#SRV_RESOLVE` | ✗ | |
| `ClickHouseClientOption#CUSTOM_SETTINGS` | | |
| `ClickHouseClientOption#PRODUCT_NAME` | ✗ | Use client name |
| `ClickHouseClientOption#RENAME_RESPONSE_COLUMN` | ✗ | |
| `ClickHouseClientOption#SERVER_REVISION` | ✗ | |
| `ClickHouseClientOption#TRANSACTION_TIMEOUT` | ✗ | |
| `ClickHouseClientOption#WIDEN_UNSIGNED_TYPES` | ✗ | |
| `ClickHouseClientOption#USE_BINARY_STRING` | ✗ | |
| `ClickHouseClientOption#USE_BLOCKING_QUEUE` | ✗ | |
| `ClickHouseClientOption#USE_COMPILATION` | ✗ | |
| `ClickHouseClientOption#USE_OBJECTS_IN_ARRAYS` | ✗ | |
| `ClickHouseClientOption#MAX_MAPPER_CACHE` | ✗ | |
| `ClickHouseClientOption#MEASURE_REQUEST_TIME` | ✗ | |

</TabItem>
</Tabs>


### General Differences

- Client V2 uses less proprietary classes to increase portability. For example, V2 works with any implementation of `java.io.InputStream` for
writing data to a server.
- Client V2 `async` settings is `off` by default. It means no extra threads and more application control over client. This setting should be `off` for majority of use cases. Enabling `async` will create a separate thread for a request. It only make sense when using application controlled
executor (see `com.clickhouse.client.api.Client.Builder#setSharedOperationExecutor`)

### Writing Data

- use any implementation of `java.io.InputStream`. V1 `com.clickhouse.data.ClickHouseInputStream` is supported but NOT recommended.
- once end of input stream is detected it handled accordingly. Previously output stream of a request should be closed.

__V1 Insert TSV formatted data.__
```java
InputStream inData = getInData();
ClickHouseRequest.Mutation request = client.read(server)
        .write()
        .table(tableName)
        .format(ClickHouseFormat.TSV);
ClickHouseConfig config = request.getConfig();
CompletableFuture<ClickHouseResponse> future;
try (ClickHousePipedOutputStream requestBody = ClickHouseDataStreamFactory.getInstance()
        .createPipedOutputStream(config)) {
    // start the worker thread which transfer data from the input into ClickHouse
    future = request.data(requestBody.getInputStream()).execute();

    // Copy data from inData stream to requestBody stream

    // We need to close the stream before getting a response
    requestBody.close();

    try (ClickHouseResponse response = future.get()) {
        ClickHouseResponseSummary summary = response.getSummary();
        Assert.assertEquals(summary.getWrittenRows(), numRows, "Num of written rows");
    }
}

V2 TSV 형식 데이터 삽입.

InputStream inData = getInData();
InsertSettings settings = new InsertSettings().setInputStreamCopyBufferSize(8198 * 2); // set copy buffer size
try (InsertResponse response = client.insert(tableName, inData, ClickHouseFormat.TSV, settings).get(30, TimeUnit.SECONDS)) {

  // Insert is complete at this point

} catch (Exception e) {
 // Handle exception
}
  • 호출할 메서드는 하나뿐입니다. 별도의 요청 객체를 생성할 필요가 없습니다.
  • 모든 데이터 복사가 완료되면 요청 본문(request body) 스트림이 자동으로 닫힙니다.
  • 새로운 저수준 API인 com.clickhouse.client.api.Client#insert(java.lang.String, java.util.List<java.lang.String>, com.clickhouse.client.api.DataStreamWriter, com.clickhouse.data.ClickHouseFormat, com.clickhouse.client.api.insert.InsertSettings)를 사용할 수 있습니다. com.clickhouse.client.api.DataStreamWriter는 사용자 정의 데이터 쓰기 로직을 구현하도록 설계되었습니다. 예를 들어 큐에서 데이터를 읽어와 쓰는 로직을 구현할 때 사용할 수 있습니다.

데이터 읽기

  • 데이터는 기본적으로 RowBinaryWithNamesAndTypes 형식으로 읽어집니다. 현재 데이터 바인딩이 필요한 경우 이 형식만 지원됩니다.
  • 데이터는 List<GenericRecord> com.clickhouse.client.api.Client#queryAll(java.lang.String) 메서드를 사용하여 레코드 컬렉션으로 읽을 수 있습니다. 이 메서드는 데이터를 메모리에 로드한 후 연결을 해제합니다. 추가 처리는 필요하지 않습니다. GenericRecord는 데이터에 접근할 수 있도록 하며, 일부 타입 변환 기능을 제공합니다.
Collection<GenericRecord> records = client.queryAll("SELECT * FROM table");
for (GenericRecord record : records) {
    int rowId = record.getInteger("rowID");
    String name = record.getString("name");
    LocalDateTime ts = record.getLocalDateTime("ts");
}

프로토콜을 통해 데이터베이스 서버와 통신하는 Java 클라이언트 라이브러리입니다. 현재 구현은 HTTP 인터페이스만 지원합니다. 이 라이브러리는 서버에 요청을 전송하기 위한 자체 API를 제공합니다.

지원 중단

이 라이브러리는 곧 지원이 중단될 예정입니다. 새 프로젝트에는 최신 Java Client를 사용하십시오.

설정

<!-- 참고: https://mvnrepository.com/artifact/com.clickhouse/clickhouse-http-client -->
<dependency>
    <groupId>com.clickhouse</groupId>
    <artifactId>clickhouse-http-client</artifactId>
    <version>0.7.2</version>
</dependency>

버전 0.5.0부터 드라이버는 별도 의존성으로 추가해야 하는 새로운 클라이언트 HTTP 라이브러리를 사용합니다.

<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents.client5/httpclient5 -->
<dependency>
    <groupId>org.apache.httpcomponents.client5</groupId>
    <artifactId>httpclient5</artifactId>
    <version>5.3.1</version>
</dependency>

초기화

연결 URL 형식: protocol://host[:port][/database][?param[=value][&param[=value]][#tag[,tag]], 예를 들어:

단일 노드에 연결하세요:

ClickHouseNode server = ClickHouseNode.of("http://localhost:8123/default?compress=0");

여러 노드로 구성된 클러스터에 연결하세요:

ClickHouseNodes servers = ClickHouseNodes.of(
    "jdbc:ch:http://server1.domain,server2.domain,server3.domain/my_db"
    + "?load_balancing_policy=random&health_check_interval=5000&failover=2");

쿼리 API

try (ClickHouseClient client = ClickHouseClient.newInstance(ClickHouseProtocol.HTTP);
     ClickHouseResponse response = client.read(servers)
        .format(ClickHouseFormat.RowBinaryWithNamesAndTypes)
        .query("select * from numbers limit :limit")
        .params(1000)
        .executeAndWait()) {
            ClickHouseResponseSummary summary = response.getSummary();
            long totalRows = summary.getTotalRowsToRead();
}

스트리밍 쿼리 API

try (ClickHouseClient client = ClickHouseClient.newInstance(ClickHouseProtocol.HTTP);
     ClickHouseResponse response = client.read(servers)
        .format(ClickHouseFormat.RowBinaryWithNamesAndTypes)
        .query("select * from numbers limit :limit")
        .params(1000)
        .executeAndWait()) {
            for (ClickHouseRecord r : response.records()) {
            int num = r.getValue(0).asInteger();
            // type conversion
            String str = r.getValue(0).asString();
            LocalDate date = r.getValue(0).asDate();
        }
}

저장소에서 전체 코드 예제를 참조하세요.

Insert API


try (ClickHouseClient client = ClickHouseClient.newInstance(ClickHouseProtocol.HTTP);
     ClickHouseResponse response = client.read(servers).write()
        .format(ClickHouseFormat.RowBinaryWithNamesAndTypes)
        .query("insert into my_table select c2, c3 from input('c1 UInt8, c2 String, c3 Int32')")
        .data(myInputStream) // `myInputStream` is source of data in RowBinary format
        .executeAndWait()) {
            ClickHouseResponseSummary summary = response.getSummary();
            summary.getWrittenRows();
}

저장소에서 전체 코드 예제를 참조하세요.

RowBinary 인코딩

RowBinary 형식은 해당 페이지에서 설명되어 있습니다.

예제 코드는 코드에서 확인할 수 있습니다.

주요 기능

압축

클라이언트는 기본적으로 LZ4 압축을 사용하며, 이를 위해 다음 의존성이 필요합니다:

<!-- 참고: https://mvnrepository.com/artifact/org.lz4/lz4-java -->
<dependency>
    <groupId>org.lz4</groupId>
    <artifactId>lz4-java</artifactId>
    <version>1.8.0</version>
</dependency>

연결 URL에서 compress_algorithm=gzip으로 설정하면 gzip을 대신 사용할 수 있습니다.

또는 압축을 비활성화하는 방법도 여러 가지가 있습니다.

  1. 연결 URL에 compress=0을 설정하여 압축을 비활성화하십시오: http://localhost:8123/default?compress=0
  2. 클라이언트 설정을 통해 비활성화하십시오:
ClickHouseClient client = ClickHouseClient.builder()
   .config(new ClickHouseConfig(Map.of(ClickHouseClientOption.COMPRESS, false)))
   .nodeSelector(ClickHouseNodeSelector.of(ClickHouseProtocol.HTTP))
   .build();

다양한 압축 옵션에 대해 자세히 알아보려면 압축 관련 문서를 참조하십시오.

여러 쿼리

동일한 세션 내에서 워커 스레드(worker thread)를 통해 여러 쿼리를 순차적으로 실행하세요:

CompletableFuture<List<ClickHouseResponseSummary>> future = ClickHouseClient.send(servers.apply(servers.getNodeSelector()),
    "create database if not exists my_base",
    "use my_base",
    "create table if not exists test_table(s String) engine=Memory",
    "insert into test_table values('1')('2')('3')",
    "select * from test_table limit 1",
    "truncate table test_table",
    "drop table if exists test_table");
List<ClickHouseResponseSummary> results = future.get();

명명된 매개변수(Named Parameters)

매개변수 목록에서의 위치에만 의존하지 않고 이름으로 매개변수를 전달할 수 있습니다. 이 기능은 params 함수를 통해 사용할 수 있습니다.

try (ClickHouseClient client = ClickHouseClient.newInstance(ClickHouseProtocol.HTTP);
     ClickHouseResponse response = client.read(servers)
        .format(ClickHouseFormat.RowBinaryWithNamesAndTypes)
        .query("select * from my_table where name=:name limit :limit")
        .params("Ben", 1000)
        .executeAndWait()) {
            //...
        }
}
매개변수

String 타입(String, String[], Map<String, String>)과 관련된 모든 params 시그니처는 전달되는 키가 유효한 ClickHouse SQL 문자열이라고 가정합니다. 예를 들어:

try (ClickHouseClient client = ClickHouseClient.newInstance(ClickHouseProtocol.HTTP);
     ClickHouseResponse response = client.read(servers)
        .format(ClickHouseFormat.RowBinaryWithNamesAndTypes)
        .query("select * from my_table where name=:name")
        .params(Map.of("name","'Ben'"))
        .executeAndWait()) {
            //...
        }
}

String 객체를 ClickHouse SQL로 수동으로 변환하고 싶지 않은 경우, com.clickhouse.data에 있는 헬퍼 함수 ClickHouseValues.convertToSqlExpression을 사용할 수 있습니다:

try (ClickHouseClient client = ClickHouseClient.newInstance(ClickHouseProtocol.HTTP);
     ClickHouseResponse response = client.read(servers)
        .format(ClickHouseFormat.RowBinaryWithNamesAndTypes)
        .query("select * from my_table where name=:name")
        .params(Map.of("name", ClickHouseValues.convertToSqlExpression("Ben's")))
        .executeAndWait()) {
            //...
        }
}

위 예제에서 ClickHouseValues.convertToSqlExpression은 문자열 내부의 작은따옴표를 이스케이프 처리하고, 변수를 유효한 작은따옴표로 둘러쌉니다.

Integer, UUID, Array, Enum 등의 다른 타입은 params 내에서 자동으로 변환됩니다.

노드 검색

Java 클라이언트는 ClickHouse 노드를 자동으로 검색할 수 있는 기능을 제공합니다. 이 자동 검색 기능은 기본적으로 비활성화되어 있습니다. 수동으로 활성화하려면 auto_discoverytrue로 설정하세요:

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

또는 연결 URL에서 다음과 같이 설정합니다:

jdbc:ch://my-server/system?auto_discovery=true

자동 검색이 활성화되어 있으면 연결 URL에 모든 ClickHouse 노드를 지정할 필요가 없습니다. URL에 지정된 노드는 시드 노드로 취급되며, Java 클라이언트는 system 테이블 및/또는 Keeper/ZooKeeper에서 추가 노드를 자동으로 검색합니다.

다음 옵션은 자동 검색 구성을 위한 설정입니다:

속성기본값설명
auto_discoveryfalse클라이언트가 system 테이블 및/또는 clickhouse-keeper 또는 ZooKeeper에서 추가 노드를 자동으로 검색할지 여부입니다.
node_discovery_interval0노드 검색 간격(밀리초)입니다. 0 이하의 값은 한 번만 검색함을 의미합니다.
node_discovery_limit100한 번에 검색할 수 있는 최대 노드 수입니다. 0 이하의 값은 제한이 없음을 의미합니다.

로드 밸런싱

Java 클라이언트는 로드 밸런싱 정책에 따라 요청을 보낼 ClickHouse 노드를 선택합니다. 일반적으로 로드 밸런싱 정책은 다음과 같은 역할을 담당합니다.

  1. 관리 중인 노드 목록에서 노드 하나를 선택합니다.
  2. 노드 상태를 관리합니다.
  3. 자동 검색이 활성화된 경우, 필요에 따라 노드 디스커버리용 백그라운드 프로세스를 스케줄링하고 헬스 체크를 실행합니다.

다음은 로드 밸런싱을 구성할 때 사용할 수 있는 옵션 목록입니다.

속성기본값설명
load_balancing_policy""로드 밸런싱 정책은 다음 중 하나일 수 있습니다:
  • firstAlive - 요청이 관리 노드 목록에서 정상 상태인 첫 번째 노드로 전송됩니다.
  • random - 요청이 관리 노드 목록에서 임의의 노드로 전송됩니다.
  • roundRobin - 요청이 관리 노드 목록의 각 노드로 차례대로 전송됩니다.
  • ClickHouseLoadBalancingPolicy를 구현하는 완전히 한정된 클래스 이름(fully qualified class name) - 사용자 정의 로드 밸런싱 정책
  • 지정하지 않으면 요청은 관리 노드 목록의 첫 번째 노드로 전송됩니다.
    load_balancing_tags""노드를 필터링하기 위한 로드 밸런싱 태그입니다. 요청은 지정된 태그를 가진 노드에만 전송됩니다.
    health_check_interval0헬스 체크 간격(밀리초)입니다. 0 이하의 값은 한 번만 수행함을 의미합니다.
    health_check_methodClickHouseHealthCheckMethod.SELECT_ONE헬스 체크 방법입니다. 다음 값 중 하나를 사용할 수 있습니다:
  • ClickHouseHealthCheckMethod.SELECT_ONE - select 1 쿼리로 헬스 체크를 수행합니다
  • ClickHouseHealthCheckMethod.PING - 프로토콜별 헬스 체크 방식으로, 일반적으로 더 빠릅니다
  • node_check_interval0노드 검사 간격(밀리초)입니다. 음수 값은 0으로 처리됩니다. 마지막 검사 이후 지정된 시간이 경과했을 때 노드 상태를 확인합니다.
    health_check_intervalnode_check_interval의 차이는, health_check_interval 옵션이 노드 목록(전체 또는 장애 노드)의 상태를 확인하는 백그라운드 작업을 스케줄링하는 반면, node_check_interval은 특정 노드에 대해 마지막 검사 이후 상태를 다시 확인하기까지 경과해야 하는 최소 시간을 지정한다는 점입니다
    check_all_nodesfalse모든 노드에 대해 헬스 체크를 수행할지, 아니면 장애가 발생한 노드에 대해서만 수행할지 여부입니다.

    장애 조치 및 재시도

    Java 클라이언트는 실패한 쿼리에 대한 장애 조치 및 재시도 동작을 설정할 수 있는 구성 옵션을 제공합니다:

    속성기본값설명
    failover0요청에 대해 장애 조치가 발생할 수 있는 최대 횟수입니다. 0 또는 음수 값은 장애 조치를 수행하지 않음을 의미합니다. 장애 조치는 장애가 발생한 요청을 복구하기 위해 부하 분산 정책에 따라 실패한 요청을 다른 노드로 전송합니다.
    retry0단일 요청에 대해 허용되는 재시도 최대 횟수입니다. 값이 0 또는 음수이면 재시도를 수행하지 않음을 의미합니다. 재시도는 ClickHouse 서버가 NETWORK_ERROR 오류 코드를 반환한 경우에만 동일한 노드로 요청을 다시 전송합니다
    repeat_on_session_locktrue세션이 잠긴 상태일 때 session_timeout 또는 connect_timeout에 따라 시간 초과가 발생할 때까지 실행을 반복할지 여부입니다. ClickHouse 서버가 SESSION_IS_LOCKED 오류 코드를 반환하면 실패한 요청을 다시 시도합니다.

    커스텀 HTTP 헤더 추가하기

    Java 클라이언트는 요청에 사용자 정의 HTTP 헤더를 추가해야 하는 경우 HTTP/S 전송 계층을 지원합니다. custom_http_headers 속성을 사용해야 합니다. 헤더 항목은 ,로 구분하고, 각 헤더의 키와 값은 =로 구분합니다.

    Java 클라이언트 지원

    options.put("custom_http_headers", "X-ClickHouse-Quota=test, X-ClickHouse-Test=test");
    

    JDBC 드라이버

    properties.setProperty("custom_http_headers", "X-ClickHouse-Quota=test, X-ClickHouse-Test=test");