Pular para o conteúdo principal
clickhouse-jdbc implementa a interface JDBC padrão usando o cliente Java mais recente. Recomendamos usar diretamente o cliente Java mais recente se o desempenho/acesso direto for crítico.

Requisitos de ambiente

Setup

Se você estiver usando o driver JDBC em uma aplicação que requer a adição do jar ao classpath, é necessário fazer o download do jar em:

Configuração

Classe do Driver: com.clickhouse.jdbc.ClickHouseDriver
com.clickhouse.jdbc.ClickHouseDriver é uma classe de fachada para as implementações JDBC nova e antiga. Ela usa a nova implementação JDBC por padrão. Você pode usar a implementação JDBC antiga definindo a propriedade system clickhouse.jdbc.v1 como true. Essa propriedade deve ser definida antes de chamar a classe Driver.Uma forma alternativa de alternar entre as versões é usar diretamente as classes Driver de cada versão:
  • com.clickhouse.jdbc.Driver é a nova implementação JDBC (V2).
  • com.clickhouse.jdbc.DriverV1 é a implementação JDBC antiga (V1).
Sintaxe de URL: jdbc:(ch|clickhouse)[:<protocol>]://endpoint[:port][/<database>][?param1=value1&param2=value2][#tag1,tag2,...], por exemplo:
  • jdbc:clickhouse:http://localhost:8123
  • jdbc:clickhouse:https://localhost:8443?ssl=true
Há alguns pontos a observar sobre a sintaxe da URL:
  • apenas um endpoint é permitido na URL
  • o protocolo deve ser especificado quando não for o padrão - ‘HTTP’
  • a porta deve ser especificada quando não for a porta padrão ‘8123’
  • o driver não detecta automaticamente o protocol pela porta, você precisa especificá-lo explicitamente
  • O parâmetro ssl não é necessário quando o protocolo é informado.

Propriedades de Conexão

Os principais parâmetros de configuração são definidos no java client. Eles devem ser repassados sem modificações ao driver. O driver possui algumas propriedades próprias que não fazem parte da configuração do cliente; elas estão listadas abaixo.Propriedades do driver:
Configurações do servidorTodas as configurações do servidor devem ser prefixadas com clickhouse_setting_ (assim como na configuração do cliente).
Exemplo de configuração:
o que será equivalente à seguinte URL JDBC:
Nota: não é necessário codificar em URL a JDBC URL ou as propriedades, pois elas serão codificadas automaticamente.Perfis somente leituraEvitamos deliberadamente adicionar configurações padrão às propriedades de conexão para evitar problemas com perfis read-only. No entanto, alguns usuários precisam passar configurações de formato (por exemplo, para ler JSON como String) e recomendamos usar o perfil readonly=2. Leia mais sobre perfis read-only aqui.

Identificação do Cliente

Há duas maneiras de identificar a aplicação que originou uma requisição: definir com.clickhouse.client.api.ClientConfigProperties#CLIENT_NAME por meio das propriedades de conexão ou utilizar o método java.sql.Connection#setClientInfo(String name, String value).
showLineNumbers
showLineNumbers
Ambas as formas resultarão no seguinte valor de http_user_agent no log de consultas:
Nota: Recomendamos usar o formato app_name/version para a propriedade client_name, pois isso ajuda a identificar a aplicação no log de consultas.

Identificação de Operação

O driver JDBC gera um query_id para cada operação (atualmente incluído nas exceções do servidor).Para definir log_comment em uma operação, utilize o método com.clickhouse.jdbc.StatementImpl#getLocalSettings. Para isso, é necessário realizar o cast de Statement ou PreparedStatement para com.clickhouse.jdbc.StatementImpl primeiro.
showLineNumbers
Nota: esta abordagem funciona para usos de instrução em thread único porque localSettings é compartilhado entre as threads.

Tipos de dados suportados

O JDBC driver suporta os mesmos formatos de dados que o java client subjacente.

Mapeamento de Tipos JDBC

O seguinte mapeamento se aplica a:
  • ResultSet#getObject(columnIndex) - o método retorna um objeto da classe Java correspondente. (Int8 -> java.lang.Byte, Int16 -> java.lang.Short, etc.)
  • ResultSetMetaData#getColumnType(columnIndex) - o método retorna o tipo JDBC correspondente. (Int8 -> java.lang.Byte, Int16 -> java.lang.Short, etc.)
Existem algumas maneiras de alterar o mapeamento:
  • ResultSet#getObject(columnIndex, class) - o método tentará converter o valor para o tipo class. Há algumas limitações de conversão. Consulte cada seção para mais detalhes.
Tipos Numéricos
  • tipos numéricos são conversíveis entre si. Portanto, Int8 pode ser convertido em Float64 e vice-versa.:
    • rs.getObject(1, Float64.class) retornará um valor Float64 da coluna Int8.
    • rs.getLong(1) retornará um valor Long da coluna Int8.
    • rs.getByte(1) pode retornar um valor Byte da coluna Int16 se ele couber em Byte.
  • a conversão de um tipo mais amplo para um mais restrito não é recomendada devido ao risco de corrupção de dados.
  • O tipo Bool também funciona como número.
  • Todos os tipos numéricos podem ser lidos como java.lang.String.
  • Armazenar Float.MAX_VALUE do Java como Float causa um problema (https://github.com/ClickHouse/clickhouse-java/issues/809). Salvar o mesmo valor como Double resolve esse problema.
Tipos String
  • String só pode ser lida como java.lang.String ou byte[].
  • FixedString é lido como está e será preenchido com zeros até atingir o comprimento da coluna. (Por exemplo, FixedString(10) para 'John' será lido como 'John\0\0\0\0\0\0\0\0\0'.)
Tipos Enum
  • Enum8 e Enum16 são mapeados para java.lang.String por padrão.
  • Valores de enum podem ser lidos como valores numéricos usando o método getter apropriado ou o método getObject(columnIndex, Integer.class).
  • Enum16 é mapeado internamente para short, e Enum8 é mapeado para byte. Deve-se evitar ler Enum16 como byte devido ao risco de corrupção de dados.
  • Valores de enum podem ser definidos como string ou valor numérico em PreparedStatement.
Tipos de Data/Hora
  • Os tipos Date / Time são mapeados para tipos java.sql para garantir melhor compatibilidade com JDBC. No entanto, é possível obter java.time.LocalDate, java.time.LocalDateTime e java.time.LocalTime usando ResultSet#getObject(columnIndex, Class<T>) com a classe correspondente como segundo argumento.
    • rs.getObject(1, java.time.LocalDate.class) retorna o valor java.time.LocalDate da coluna Date.
    • rs.getObject(1, java.time.LocalDateTime.class) retorna o valor java.time.LocalDateTime da coluna DateTime.
    • rs.getObject(1, java.time.LocalTime.class) retorna o valor java.time.LocalTime da coluna Time.
  • Date, Date32, Time, Time64 não são afetados pelo fuso horário do servidor.
  • DateTime e DateTime64 são afetados pelo fuso horário do servidor ou da sessão.
  • DateTime e DateTime64 podem ser obtidos como ZonedDateTime usando getObject(colIndex, ZonedDateTime.class).
Tipos Aninhados
  • Array é mapeado para java.sql.Array por padrão para garantir compatibilidade com JDBC. Isso também é feito para fornecer mais informações sobre o valor do array retornado. É útil para inferência de tipos.
  • Array implementa o método getResultSet() para retornar um java.sql.ResultSet com o mesmo conteúdo do array original.
  • Tipos de coleção não devem ser lidos como java.lang.String, porque essa não é uma forma válida de representar os dados (ex.: em arrays, não há aspas para valores de string).
  • Map é mapeado para OTHER porque o valor só pode ser lido com o método getObject(columnIndex, Class<T>).
    • Map não é um java.sql.Struct porque não possui colunas nomeadas.
  • Tuple é mapeado para Object[] porque pode conter diferentes tipos, e usar List não é válido.
  • Tuple pode ser interpretado como Array usando o método getObject(columnIndex, Array.class). Nesse caso, Array#baseTypeName retornará a definição da coluna Tuple.
Metadados do Tipo de Elemento do ArrayArray.getBaseTypeName() retorna o nome do tipo de elemento do ClickHouse; Array.getBaseType() retorna o código de tipo JDBC. O JDBC V2 preserva as assinaturas completas de tipo (tipos encapsulados, parâmetros de tipo) que o V1 remove.As regras gerais de mapeamento para arrays são:Notes on the rules above:
  • Tipos encapsuladores (Nullable, LowCardinality) são preservados em getBaseTypeName(), mas getBaseType() é resolvido para o código JDBC do tipo interno.
  • Arrays aninhados são achatados nos metadados: getBaseTypeName() retorna o tipo do elemento mais interno que não é array, e não o filho imediato.
  • Tipos parametrizados (FixedString(N), definições completas de Enum/Tuple) mantêm seus parâmetros em getBaseTypeName().
Exemplos:
  • Na V2, getBaseTypeName() preserva a assinatura completa do tipo, incluindo tipos encapsuladores (Nullable, LowCardinality) e parâmetros de tipo (FixedString(8), definições completas de Enum e Tuple). A V1 remove esses elementos e retorna apenas o nome do tipo básico.
  • Arrays de Tuple usam OTHER (1111) na V2 em vez de STRUCT (2002) porque as tuplas do ClickHouse têm campos nomeados, o que java.sql.Struct não suporta.
  • Arrays de UUID usam OTHER (1111) na V2, seguindo o mesmo mapeamento escalar de UUID.
  • Valores de Enum são mapeados para VARCHAR — os membros do enum são identificados pelo nome da string, independentemente da codificação numérica subjacente.
Escrevendo ArraysUse java.sql.Connection#createArrayOf para instanciar o objeto java.sql.Array. Esse objeto foi projetado para unificar o tratamento de arrays em diferentes bancos de dados. A conexão é necessária para passar a configuração ao método de fábrica do Array.O método aceita dois argumentos:
  • typeName - nome do tipo dos elementos da matriz. Por exemplo, Array(Int32) -> "Int32".
  • elements - elementos do array propriamente ditos. Por exemplo [[1, 2, 3], [4, 5, 6]] -> new Integer[][] {{1, 2, 3}, {4, 5, 6}}.
Tuple pode ser representado como Object[] ou como java.sql.Struct (veja como escrever tuples abaixo).Exemplo
Lendo ArraysUse ResultSet#getArray(columnIndex) para ler o objeto Array. O objeto pode ser usado para acessar arrays de qualquer nível de aninhamento. O método Array#getResultSet() pode ser usado para ler elementos de array de forma mais unificada como java.sql.ResultSet. Isso é útil quando o tipo exato dos elementos do array não é conhecido.Exemplo
Escrevendo TuplesTuples são mapeados para o objeto com.clickhouse.data.Tuple e devem ser escritos como esse objeto por meio da chamada ao método setObject(columnIndex, tuple). É possível usar o objeto java.sql.Struct para escrever tuples com maior portabilidade.Exemplo
Lendo TuplesO método getObject(columnIndex) retornará Object[]. Tuples podem ser lidas como java.sql.Array usando o método getObject(columnIndex, Array.class).Exemplo
Escrevendo MapsMap só pode ser escrito como um objeto java.collections.Map porque esse tipo exige pares chave-valor (java.sql.Struct não suporta pares chave-valor).Exemplo
Lendo MapasMap pode ser lido como um objeto java.collections.Map usando o método getObject(columnIndex, Map.class).Exemplo
Gravando Dados AninhadosUse java.sql.Connection#createStruct para instanciar o objeto java.sql.Struct. Esse objeto foi projetado para unificar o tratamento de tipos aninhados em diferentes bancos de dados. A conexão é necessária para passar a configuração ao método de fábrica do Struct.O método aceita dois argumentos:
  • typeName - nome do tipo dos elementos internos. Por exemplo, Nested(Tuple(Int32, String)) -> "Nested(Tuple(Int32, String))".
  • elements - os elementos aninhados reais. Por exemplo, [1, 'test'] -> new Object[] {1, 'test'}.
Exemplo
Lendo Dados NestedUse ResultSet#getStruct(columnIndex, StructDescriptor) para ler o objeto Nested. O objeto pode ser usado para acessar elementos aninhados em qualquer nível de profundidade. O método Struct#getResultSet() pode ser usado para ler elementos aninhados de forma mais unificada como java.sql.ResultSet. Isso é útil quando o tipo exato dos elementos aninhados não é conhecido.Exemplo
Geo TypesTipos Nullable e LowCardinality
  • Nullable e LowCardinality são tipos especiais que envolvem outros tipos.
  • Nullable afeta como os nomes dos tipos são retornados em ResultSetMetaData
Tipos Especiais
  • UUID não é um tipo padrão do JDBC. No entanto, faz parte do JDK. Por padrão, java.util.UUID é retornado pelo método getObject().
  • UUID pode ser lido e gravado como String usando o método getObject(columnIndex, String.class).
  • IPv4 e IPv6 não são tipos padrão do JDBC. No entanto, fazem parte do JDK. Por padrão, java.net.Inet4Address e java.net.Inet6Address são retornados pelo método getObject().
  • IPv4 e IPv6 podem ser lidos/gravados como String por meio do método getObject(columnIndex, String.class).
Tipo JSONO tipo JSON é mapeado para Map<String, Object> por padrão, onde as chaves são as chaves do objeto JSON e os valores são os valores do objeto JSON. Por exemplo:
will be mapped to:
Há uma opção mais conveniente para ler JSON como String passando a configuração do servidor jdbc_read_json_as_string=true nas propriedades de conexão. Isso faz com que o driver retorne valores JSON como String, que podem ser analisados usando qualquer biblioteca JSON.
A partir da versão 25.8 do ClickHouse, os números não são mais colocados entre aspas por padrão. Para versões anteriores, você pode desativar as aspas passando configurações do servidor para as propriedades de conexão:

Tratamento de Datas, Horas e Fusos Horários

Leia o Guia de Date/Time, que explica armadilhas comuns e a lógica do driver ao lidar com Date/Time e timestamps.

Criando Conexão

Fornecendo Credenciais e Configurações

showLineNumbers

Instrução Simples

showLineNumbers

Insert

showLineNumbers

HikariCP

showLineNumbers

Mais Informações

Para mais informações, consulte nosso repositório do GitHub e a documentação do Java Client.

Solução de problemas

Logging

O driver usa slf4j para logging e usará a primeira implementação disponível no classpath.

Resolvendo Timeout JDBC em Inserts de Grande Volume

Ao realizar grandes inserções no ClickHouse com longos tempos de execução, você pode se deparar com erros de timeout JDBC como:
Esses erros podem interromper o processo de inserção de dados e afetar a estabilidade do sistema. Para resolver esse problema, pode ser necessário ajustar algumas configurações de timeout no SO do cliente.

Mac OS

No macOS, as seguintes configurações podem ser ajustadas para resolver o problema:
  • 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

No Linux, as configurações equivalentes por si só podem não resolver o problema. Etapas adicionais são necessárias devido às diferenças na forma como o Linux trata as configurações de keep-alive de socket. Siga estas etapas:
  1. Ajuste os seguintes parâmetros do kernel do Linux em /etc/sysctl.conf ou em um arquivo de configuração relacionado:
  • 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 (Você pode considerar reduzir esse valor em relação ao valor padrão de 300 segundos)
  1. Após modificar os parâmetros do kernel, aplique as alterações executando o seguinte comando:
Após definir essas configurações, você precisa garantir que seu cliente habilite a opção Keep Alive no socket:

Guia de Migração

Principais Alterações

  • O JDBC V2 foi implementado para ser mais leve e algumas funcionalidades foram removidas.
    • Dados de streaming não têm suporte no JDBC V2 porque não fazem parte da especificação do JDBC nem do Java.
  • O JDBC V2 exige configuração explícita. Não há failover por padrão.
    • O protocolo deve ser especificado na URL. Sem detecção implícita do protocolo com base em números de porta.

Alterações de Configuração

Existem apenas dois enums:
  • com.clickhouse.jdbc.DriverProperties - as propriedades de configuração do driver.
  • com.clickhouse.client.api.ClientConfigProperties - as propriedades de configuração do cliente. As alterações na configuração do cliente são descritas na documentação do cliente Java.
As propriedades de conexão são interpretadas da seguinte forma:
  • A URL é analisada primeiro para identificar as propriedades. Elas sobrescrevem todas as demais propriedades.
  • As propriedades do driver não são enviadas ao cliente.
  • Os endpoints (host, port, protocol) são extraídos da URL.
Exemplo:

Alterações nos Tipos de Dados

Tipos Numéricos
  • A principal diferença é que os tipos sem sinal são mapeados para tipos Java para melhor portabilidade.
Tipos String
  • FixedString é lido exatamente como está em ambas as versões. Por exemplo, FixedString(10) para 'John' será lido como 'John\0\0\0\0\0\0\0\0\0'.
  • Quando PreparedStatement#setBytes for usado, ele será convertido em unhex('<hex_string>') e depois lido como String.
  • Strings são armazenadas na codificação UTF-8.
Tipos de Data/Hora
  • Time e Time64 têm suporte no V2 apenas como novos tipos.
  • DateTime e DateTime64 são mapeados para java.sql.Timestamp para garantir melhor compatibilidade com JDBC.
Tipos EnumTipos Aninhados
  • Na V2, Array é mapeado para java.sql.Array por padrão para manter a compatibilidade com o JDBC. Isso também é feito para fornecer mais informações sobre o valor de array retornado. Útil para inferência de tipos.
  • Na V2, Array implementa o método getResultSet() para retornar um java.sql.ResultSet com o mesmo conteúdo do array original.
  • A V1 usa STRUCT para Map, mas sempre retorna um objeto java.util.Map. A V2 corrige isso ao mapear Map para JAVA_OBJECT.
  • A V1 usa STRUCT para Tuple, mas sempre retorna uma List<Object>. A V2 mapeia Tuple para OTHER e retorna Object[] por padrão.
  • A V2 introduz com.clickhouse.data.Tuple#Tuple para gravar tuplas. Isso facilita determinar se o valor é uma tupla ou um array.
  • PreparedStatement#setBytes e ResultSet#getBytes não podem ser usados com tipos de coleção. Esses métodos foram concebidos para funcionar com strings binárias.
  • Normalmente, java.sql.Array é usado para gravar e ler tipos Array. O driver JDBC oferece suporte completo a isso.
  • O V2 Nested é mapeado para Array e é apresentado como um array de tuplas.
  • O V2 tem suporte parcial a java.sql.Struct porque é muito semelhante ao tipo Array e não oferece suporte a pares chave-valor. Struct pode ser usado para escrever valores Tuple.
Geo TypesTipos Nullable e LowCardinality
  • Nullable e LowCardinality são tipos especiais que envolvem outros tipos.
  • Nenhuma alteração é feita nesses tipos na V2.
Tipos Especiais
  • A V1 usa VARCHAR para UUID, mas sempre retorna um objeto java.util.UUID. A V2 corrige isso mapeando UUID para OTHER e retornando um objeto java.util.UUID.
  • A V1 usa VARCHAR para IPv4 e IPv6, mas sempre retorna objetos java.net.Inet4Address e java.net.Inet6Address. A V2 corrige isso ao mapear IPv4 e IPv6 para OTHER e retornar objetos java.net.Inet4Address e java.net.Inet6Address.
  • Dynamic e Variant são novos tipos na V2. Não são compatíveis com a V1.
  • JSON baseia-se no tipo Dynamic. Portanto, tem suporte apenas no V2.
  • Os valores de IPv4 e IPv6 podem ser lidos como byte[] usando o método getBytes(columnIndex). No entanto, recomenda-se usar classes específicas para esses tipos.
  • V2 não oferece suporte à leitura de endereços IP como valores numéricos, porque essa conversão é implementada de forma mais adequada nas classes InetAddress.

Alterações de Metadados do Banco de Dados

  • O V2 usa apenas o termo Schema para nomear bancos de dados. O termo Catalog fica reservado para uso futuro.
  • A V2 retorna false para DatabaseMetaData.supportsTransactions() e DatabaseMetaData.supportsSavepoints(). Isso será alterado em versões futuras.
  • Em DatabaseMetaData.getTypeInfo(), as colunas LITERAL_PREFIX e LITERAL_SUFFIX agora retornam null para tipos de dados nos quais não se esperam prefixos e sufixos (por exemplo, tipos numéricos). Na V1, essas colunas retornavam valores não nulos para esses tipos. Essas colunas devem ser usadas ao gerar consultas SQL para delimitar corretamente valores literais de acordo com seu tipo de dado.
Última modificação em 2 de julho de 2026