Passer au contenu principal
clickhouse-jdbc implémente l’interface JDBC standard en s’appuyant sur le dernier client Java. Nous recommandons d’utiliser directement le dernier client Java si les performances ou l’accès direct sont essentiels.

Prérequis environnementaux

Configuration

Si vous utilisez le pilote JDBC dans une application nécessitant l’ajout d’un jar au classpath, vous devez télécharger le jar depuis :

Configuration

Classe du driver: com.clickhouse.jdbc.ClickHouseDriver
com.clickhouse.jdbc.ClickHouseDriver est une classe de façade pour les nouvelles et anciennes implémentations JDBC. Elle utilise par défaut la nouvelle implémentation JDBC. Vous pouvez utiliser l’ancienne implémentation JDBC en définissant la propriété système clickhouse.jdbc.v1 sur true. Cette propriété doit être définie avant tout appel à la classe Driver.Une autre façon de basculer entre les versions consiste à utiliser directement les classes Driver de chaque version :
  • com.clickhouse.jdbc.Driver est la nouvelle implémentation JDBC (V2).
  • com.clickhouse.jdbc.DriverV1 est l’ancienne implémentation JDBC (V1).
Syntaxe d’URL : jdbc:(ch|clickhouse)[:<protocol>]://endpoint[:port][/<database>][?param1=value1&param2=value2][#tag1,tag2,...], par exemple :
  • jdbc:clickhouse:http://localhost:8123
  • jdbc:clickhouse:https://localhost:8443?ssl=true
Voici quelques points à noter concernant la syntaxe des URL :
  • un seul endpoint est autorisé dans l’URL
  • le protocole doit être spécifié lorsqu’il ne s’agit pas du protocole par défaut - ‘HTTP’
  • le port doit être spécifié lorsqu’il ne s’agit pas du port par défaut ‘8123’
  • le driver ne déduit pas le protocole à partir du port, vous devez le spécifier explicitement
  • le paramètre ssl n’est pas requis lorsque le protocole est spécifié.

Propriétés de connexion

Les principaux paramètres de configuration sont définis dans le client Java. Ils doivent être transmis tels quels au driver. Le driver possède également des propriétés qui lui sont propres et qui ne font pas partie de la configuration du client ; elles sont listées ci-dessous.Propriétés du driver :
Paramètres du serveurTous les paramètres du serveur doivent être précédés du préfixe clickhouse_setting_ (comme pour la configuration du client).
Exemple de configuration :
ce qui sera équivalent à l’URL JDBC suivante :
Note : inutile d’encoder l’URL JDBC ou les propriétés en URL, elles seront encodées automatiquement.Profils en lecture seuleNous évitons délibérément d’ajouter des paramètres par défaut aux propriétés de connexion afin d’éviter tout problème avec les profils en lecture seule. Cependant, certains utilisateurs ont besoin de transmettre des paramètres de format (par exemple pour lire du JSON en tant que String) et nous recommandons d’utiliser le profil readonly=2. Pour en savoir plus sur les profils en lecture seule, consultez cette page.

Identification du client

Il existe deux façons d’identifier l’application à l’origine d’une requête : définir com.clickhouse.client.api.ClientConfigProperties#CLIENT_NAME via les propriétés de connexion ou utiliser la méthode java.sql.Connection#setClientInfo(String name, String value).
showLineNumbers
showLineNumbers
Les deux méthodes produiront la valeur http_user_agent suivante dans le journal des requêtes :
Note : Nous recommandons d’utiliser le format app_name/version pour la propriété client_name, car cela facilite l’identification de l’application dans le journal des requêtes.

Identification des opérations

Le pilote JDBC génère un query_id pour chaque opération (actuellement inclus dans les exceptions du serveur).Pour définir log_comment pour une opération, utilisez la méthode com.clickhouse.jdbc.StatementImpl#getLocalSettings. Cela nécessite que Statement ou PreparedStatement soit préalablement casté en com.clickhouse.jdbc.StatementImpl.
showLineNumbers
Note : cette approche fonctionne pour les utilisations mono-thread d’une instruction, car localSettings est partagé entre les threads.

Types de données pris en charge

Le JDBC driver prend en charge les mêmes formats de données que le java client sous-jacent.

Correspondance de types JDBC

La correspondance suivante s’applique à :
  • ResultSet#getObject(columnIndex) - la méthode retourne un objet de la classe Java correspondante. (Int8 -> java.lang.Byte, Int16 -> java.lang.Short, etc.)
  • ResultSetMetaData#getColumnType(columnIndex) - la méthode retourne le type JDBC correspondant. (Int8 -> java.lang.Byte, Int16 -> java.lang.Short, etc.)
Il existe plusieurs façons de modifier la correspondance :
  • ResultSet#getObject(columnIndex, class) - la méthode essaiera de convertir la valeur en type class. Certaines conversions présentent des limitations. Voir chaque section pour plus de détails.
Types numériques
  • les types numériques sont convertibles entre eux. Ainsi, Int8 peut être lu comme Float64, et inversement.:
    • rs.getObject(1, Float64.class) renverra une valeur Float64 pour la colonne Int8.
    • rs.getLong(1) renverra une valeur Long pour la colonne Int8.
    • rs.getByte(1) peut renvoyer une valeur Byte pour la colonne Int16 si celle-ci tient dans Byte.
  • la conversion d’un type plus large vers un type plus étroit n’est pas recommandée en raison du risque de corruption des données.
  • Le type Bool se comporte aussi comme un nombre.
  • Tous les types numériques peuvent également être lus comme java.lang.String.
  • Le stockage de Float.MAX_VALUE de Java en tant que Float pose problème (https://github.com/ClickHouse/clickhouse-java/issues/809). Enregistrer la même valeur en tant que Double résout le problème.
Types String
  • String ne peut être lu que sous la forme de java.lang.String ou de byte[].
  • FixedString est lu tel quel et sera complété par des zéros jusqu’à atteindre la longueur de la colonne. (Par exemple, FixedString(10) pour 'John' sera lu comme 'John\0\0\0\0\0\0\0\0\0'.)
Types enum
  • Enum8 et Enum16 sont associés à java.lang.String par défaut.
  • Les valeurs d’énumération peuvent être lécues comme valeurs numériques à l’aide de la méthode d’accès dédiée ou de la méthode getObject(columnIndex, Integer.class).
  • Enum16 est associé en interne à short et Enum8 à byte. Il faut éviter de lire Enum16 comme un byte en raison du risque de corruption des données.
  • Les valeurs d’énumération peuvent être définies comme chaîne de caractères ou comme valeur numérique dans PreparedStatement.
Types Date/Heure
  • Les types Date / Time sont associés aux types java.sql pour une meilleure compatibilité avec JDBC. Cependant, il est possible d’obtenir des objets java.time.LocalDate, java.time.LocalDateTime ou java.time.LocalTime en utilisant ResultSet#getObject(columnIndex, Class<T>) avec la classe correspondante comme deuxième argument.
    • rs.getObject(1, java.time.LocalDate.class) renvoie la valeur java.time.LocalDate de la colonne Date.
    • rs.getObject(1, java.time.LocalDateTime.class) renvoie la valeur java.time.LocalDateTime de la colonne DateTime.
    • rs.getObject(1, java.time.LocalTime.class) renvoie la valeur java.time.LocalTime de la colonne Time.
  • Date, Date32, Time, Time64 ne sont pas affectés par le fuseau horaire du serveur.
  • DateTime, DateTime64 sont affectés par le fuseau horaire du serveur ou le fuseau horaire de la session.
  • DateTime et DateTime64 peuvent être récupérés sous forme de ZonedDateTime à l’aide de getObject(colIndex, ZonedDateTime.class).
Types imbriqués
  • Array est mappé à java.sql.Array par défaut afin d’être compatible avec JDBC. Cela permet également de fournir plus d’informations sur la valeur de tableau renvoyée. Utile pour l’inférence de type.
  • Array implémente la méthode getResultSet() pour renvoyer un java.sql.ResultSet contenant les mêmes données que le tableau d’origine.
  • Les types de collection ne doivent pas être lus comme des java.lang.String, car ce n’est pas une manière valide de représenter les données (par ex., les valeurs de chaîne ne sont pas entre guillemets dans un tableau).
  • Map est associé à OTHER, car la valeur ne peut être lue qu’avec la méthode getObject(columnIndex, Class<T>).
    • Map n’est pas un java.sql.Struct, car il ne comporte pas de colonnes nommées.
  • Tuple est associé à Object[], car il peut contenir différents types et qu’utiliser List n’est pas possible.
  • Tuple peut être lu comme un Array à l’aide de la méthode getObject(columnIndex, Array.class). Dans ce cas, Array#baseTypeName renverra la définition de la colonne Tuple.
Métadonnées du type d’élément de tableauArray.getBaseTypeName() renvoie le nom du type d’élément ClickHouse ; Array.getBaseType() renvoie le code de type JDBC. JDBC V2 préserve les signatures de type complètes (types wrapper, paramètres de type) que V1 supprime.Les règles générales de correspondance pour les arrays sont :Remarques sur les règles ci-dessus :
  • Les types enveloppes (Nullable, LowCardinality) sont préservés dans getBaseTypeName(), mais getBaseType() correspond au code JDBC du type interne.
  • Les tableaux imbriqués sont aplatis dans les métadonnées : getBaseTypeName() renvoie le type de l’élément le plus interne qui n’est pas un tableau, et non l’élément enfant immédiat.
  • Les types paramétrés (FixedString(N), définitions complètes de Enum/Tuple) conservent leurs paramètres dans getBaseTypeName().
Exemples :
  • Dans V2, getBaseTypeName() conserve la signature de type complète, y compris les types wrapper (Nullable, LowCardinality) et les paramètres de type (FixedString(8), définitions complètes de Enum et Tuple). V1 les supprime et renvoie uniquement le nom du type de base.
  • Les tableaux Tuple utilisent OTHER (1111) dans V2 au lieu de STRUCT (2002), car les tuples ClickHouse ont des champs nommés, ce que java.sql.Struct ne prend pas en charge.
  • Les tableaux UUID utilisent OTHER (1111) dans V2, comme pour le mappage du UUID scalaire.
  • Les valeurs Enum sont mappées vers VARCHAR — les membres d’enum sont identifiés par leur nom sous forme de chaîne, indépendamment de leur encodage numérique sous-jacent.
Écriture des ArraysUtilisez java.sql.Connection#createArrayOf pour instancier un objet java.sql.Array. Cet objet est conçu pour uniformiser la gestion des tableaux entre différentes bases de données. Une connexion est nécessaire pour transmettre la configuration à la méthode factory d’Array.La méthode accepte deux arguments :
  • typeName - nom du type des éléments du tableau. Par exemple Array(Int32) -> "Int32".
  • elements - éléments effectifs du tableau. Par exemple [[1, 2, 3], [4, 5, 6]] -> new Integer[][] {{1, 2, 3}, {4, 5, 6}}.
Tuple peut être représenté sous la forme Object[] ou java.sql.Struct (voir comment écrire des tuples ci-dessous).Exemple
Lecture des ArraysUtilisez ResultSet#getArray(columnIndex) pour lire un objet Array. Cet objet permet d’accéder à un tableau quelle que soit sa profondeur d’imbrication. La méthode Array#getResultSet() peut être utilisée pour lire les éléments du tableau de façon plus uniforme sous forme de java.sql.ResultSet. Elle est utile lorsque le type exact des éléments du tableau est inconnu.Exemple
Écriture de TuplesLes Tuples sont mappés à l’objet com.clickhouse.data.Tuple et doivent être écrits sous cette forme en appelant la méthode setObject(columnIndex, tuple). Il est possible d’utiliser l’objet java.sql.Struct pour écrire des tuples et améliorer la portabilité.Exemple
Lecture de tuplesLa méthode getObject(columnIndex) renvoie Object[]. Les Tuples peuvent être lus en tant que java.sql.Array via la méthode getObject(columnIndex, Array.class).Exemple
Écriture de MapsMap ne peut être écrit qu’en tant qu’objet java.collections.Map, car ce type nécessite des paires clé-valeur (java.sql.Struct ne prend pas en charge les paires clé-valeur).Exemple
Lecture des MapsMap peut être lu en tant qu’objet java.collections.Map via la méthode getObject(columnIndex, Map.class).Exemple
Écriture dans NestedUtilisez java.sql.Connection#createStruct pour instancier un objet java.sql.Struct. Cet objet est conçu pour unifier la gestion des types imbriqués entre différentes bases de données. Une connexion est nécessaire pour transmettre la configuration à la méthode factory de Struct.La méthode accepte deux arguments :
  • typeName - nom du type des éléments imbriqués. Par exemple Nested(Tuple(Int32, String)) -> "Nested(Tuple(Int32, String))".
  • elements - éléments imbriqués proprement dits. Par exemple [1, 'test'] -> new Object[] {1, 'test'}.
Exemple
Lecture de NestedUtilisez ResultSet#getStruct(columnIndex, StructDescriptor) pour lire un objet Nested. Cet objet permet d’accéder à des éléments imbriqués quelle que soit leur profondeur d’imbrication. La méthode Struct#getResultSet() permet de lire les éléments imbriqués de façon plus uniforme sous forme de java.sql.ResultSet. Elle est utile lorsque le type exact des éléments imbriqués est inconnu.Exemple
Geo TypesTypes Nullable et LowCardinality
  • Nullable et LowCardinality sont des types spéciaux qui encapsulent d’autres types.
  • Nullable influe sur la manière dont les noms de type sont renvoyés dans ResultSetMetaData
Types spéciaux
  • UUID n’est pas un type JDBC standard. Il fait toutefois partie du JDK. Par défaut, la méthode getObject() renvoie un java.util.UUID.
  • UUID peut être lu/écrit sous forme de String à l’aide de la méthode getObject(columnIndex, String.class).
  • IPv4 et IPv6 ne sont pas des types JDBC standard. Ils font toutefois partie du JDK. Par défaut, la méthode getObject() renvoie un java.net.Inet4Address et un java.net.Inet6Address.
  • IPv4 et IPv6 peuvent être lus/écrits sous forme de String à l’aide de la méthode getObject(columnIndex, String.class).
Type JSONLe type JSON est mappé sur Map<String, Object> par défaut, où les clés sont les clés de l’objet JSON et les valeurs sont les valeurs de l’objet JSON. Par exemple :
sera associé à :
Il existe une option plus pratique pour lire le JSON en tant que String en passant le server setting jdbc_read_json_as_string=true aux properties de connexion. Cela permet au driver de retourner les values JSON en tant que String, qui peuvent ensuite être parsées à l’aide de n’importe quelle bibliothèque JSON.
À partir de la version 25.8 de ClickHouse, les nombres ne sont plus mis entre guillemets par défaut. Pour les versions antérieures, vous pouvez désactiver cette mise entre guillemets en transmettant des paramètres serveur aux propriétés de connexion :

Gestion des dates, des heures et des fuseaux horaires

Veuillez consulter le Guide Date/Time, qui explique les pièges courants et la logique du driver lors de la gestion des valeurs Date/Time et des timestamps.

Création d’une connexion

Fournir les identifiants et les paramètres

showLineNumbers

Instruction simple

showLineNumbers

Insert

showLineNumbers

HikariCP

showLineNumbers

Pour aller plus loin

Pour plus d’informations, consultez notre dépôt GitHub et la documentation du client Java.

Résolution des problèmes

Journalisation

Le driver utilise slf4j pour la journalisation et utilisera la première implémentation disponible sur le classpath.

Résolution du timeout JDBC sur les insertions volumineuses

Lors de l’exécution de grands inserts dans ClickHouse avec de longs temps d’exécution, vous pouvez rencontrer des erreurs de timeout JDBC du type :
Ces erreurs peuvent perturber le processus d’insertion de données et affecter la stabilité du système. Pour résoudre ce problème, vous devrez peut-être ajuster quelques paramètres de timeout dans le système d’exploitation du client.

Mac OS

Sur Mac OS, les paramètres suivants peuvent être modifiés pour résoudre le problème :
  • 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

Sur Linux, les paramètres équivalents seuls peuvent ne pas suffire à résoudre le problème. Des étapes supplémentaires sont nécessaires en raison des différences dans la manière dont Linux gère les paramètres keep-alive des sockets. Suivez ces étapes :
  1. Ajustez les paramètres suivants du noyau Linux dans /etc/sysctl.conf ou dans un fichier de configuration connexe :
  • 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 (Vous pouvez envisager d’abaisser cette valeur par rapport à la valeur default de 300 secondes)
  1. Après avoir modifié les paramètres du noyau, appliquez les modifications en exécutant la commande suivante :
Après avoir configuré ces paramètres, assurez-vous que votre client active l’option Keep Alive sur le socket :

Guide de migration

Modifications principales

  • JDBC V2 a été conçu pour être plus léger, et certaines fonctionnalités ont été supprimées.
    • JDBC V2 ne prend pas en charge les données en streaming, car elles ne font partie ni de la spécification JDBC ni de Java.
  • JDBC V2 nécessite une configuration explicite. Aucun basculement n’est défini par défaut.
    • Le protocole doit être indiqué dans l’URL. Aucune détection implicite du protocole en fonction du numéro de port.

Modifications de configuration

Il n’existe que deux enums :
  • com.clickhouse.jdbc.DriverProperties - les propriétés de configuration propres au driver.
  • com.clickhouse.client.api.ClientConfigProperties - les propriétés de configuration du client. Les changements de configuration du client sont décrits dans la documentation du client Java.
Les propriétés de connexion sont analysées de la manière suivante :
  • L’URL est d’abord analysée pour les propriétés. Celles-ci remplacent toutes les autres propriétés.
  • Les propriétés du driver ne sont pas transmises au client.
  • Les endpoints (hôte, port, protocole) sont extraits de l’URL.
Exemple :

Modifications des types de données

Types numériques
  • La principale différence est que les types non signés sont associés à des types Java pour une meilleure portabilité.
Types String
  • FixedString est lu tel quel dans les deux versions. Par exemple, FixedString(10) pour 'John' sera lu sous la forme 'John\0\0\0\0\0\0\0\0\0'.
  • Lorsque PreparedStatement#setBytes est utilisé, il est converti en unhex('<hex_string>'), puis lu en tant que String.
  • Les chaînes sont stockées en encodage UTF-8.
Types Date/Heure
  • Time et Time64 sont pris en charge dans V2 uniquement en tant que nouveaux types.
  • DateTime et DateTime64 sont associés à java.sql.Timestamp pour une meilleure compatibilité avec JDBC.
Types enumTypes imbriqués
  • En V2, Array est associé à java.sql.Array par défaut pour assurer la compatibilité avec JDBC. Cela permet aussi de fournir davantage d’informations sur la valeur de tableau renvoyée. Utile pour l’inférence de type.
  • En V2, Array implémente la méthode getResultSet() afin de renvoyer un java.sql.ResultSet avec le même contenu que le tableau d’origine.
  • V1 utilise STRUCT pour Map, mais renvoie toujours un objet java.util.Map. V2 corrige cela en associant Map à JAVA_OBJECT.
  • V1 utilise STRUCT pour Tuple, mais renvoie toujours un objet List<Object>. V2 associe Tuple à OTHER et renvoie Object[] par défaut.
  • V2 introduit com.clickhouse.data.Tuple#Tuple pour écrire des tuples. Cela permet de déterminer plus facilement si une valeur est un tuple ou un tableau.
  • PreparedStatement#setBytes et ResultSet#getBytes ne peuvent pas être utilisés avec des types de collection. Ces méthodes sont conçues pour fonctionner avec des chaînes binaires.
  • En général, java.sql.Array est utilisé pour écrire et lire les types Array. Le pilote JDBC le prend entièrement en charge.
  • En V2, Nested est associé à Array et est présenté comme un tableau de tuples.
  • V2 prend partiellement en charge java.sql.Struct, car il est très similaire au type Array et ne prend pas en charge les paires clé-valeur. Struct peut être utilisé pour écrire des valeurs Tuple.
Geo TypesTypes Nullable et LowCardinality
  • Nullable et LowCardinality sont des types spéciaux qui encapsulent d’autres types.
  • Aucun changement n’est apporté à ces types dans V2.
Types spéciaux
  • V1 utilise VARCHAR pour UUID, mais renvoie toujours un objet java.util.UUID. V2 corrige cela en associant UUID à OTHER et renvoie un objet java.util.UUID.
  • V1 utilise VARCHAR pour IPv4 et IPv6, mais renvoie toujours des objets java.net.Inet4Address et java.net.Inet6Address. V2 corrige cela en associant IPv4 et IPv6 à OTHER et renvoie des objets java.net.Inet4Address et java.net.Inet6Address.
  • Dynamic et Variant sont de nouveaux types dans V2. Ils ne sont pas pris en charge dans V1.
  • JSON est basé sur le type Dynamic. Il n’est donc pris en charge que dans V2.
  • Les valeurs IPv4 et IPv6 peuvent être lues sous forme de byte[] à l’aide de la méthode getBytes(columnIndex). Il est toutefois recommandé d’utiliser les classes prévues pour ces types.
  • V2 ne prend pas en charge la lecture d’une adresse IP sous forme de valeurs numériques, car la conversion est mieux gérée dans les classes InetAddress.

Modifications des métadonnées de la base de données

  • V2 utilise uniquement le terme Schema pour désigner les bases de données. Le terme Catalog est réservé à un usage futur.
  • V2 renvoie false pour DatabaseMetaData.supportsTransactions() et DatabaseMetaData.supportsSavepoints(). Cela sera modifié dans une future version.
  • Dans DatabaseMetaData.getTypeInfo(), les colonnes LITERAL_PREFIX et LITERAL_SUFFIX renvoient désormais null pour les types de données auxquels des préfixes et suffixes ne s’appliquent pas (par ex., les types numériques). Dans V1, ces colonnes renvoyaient des valeurs non nulles pour ces types. Ces colonnes doivent être utilisées lors de la génération de requêtes SQL afin de mettre correctement entre guillemets les valeurs littérales en fonction de leur type de données.
Dernière modification le 2 juillet 2026