Skip to main content
Spring Boot se connecte à Postgres via le driver JDBC PostgreSQL (pgjdbc) et un pool de connexions HikariCP, et exécute les migrations Flyway au démarrage de l’application. Dans ce guide, vous allez créer une table todos à l’aide d’une migration Flyway, puis traiter les requêtes de création, de lecture, de mise à jour et de suppression à partir d’un contrôleur REST Spring Data JPA. Toutes les connexions utilisent TLS avec vérification complète des certificats.

Prérequis

  • JDK 17 ou version ultérieure, comme l’exige Spring Boot 4. Ce guide a été testé avec Java 25, Spring Boot 4.1.1, pgjdbc 42.7.13, Hibernate 7.4.5, HikariCP 7.0.2 et Flyway 12.4.0.
  • Un compte ClickHouse Cloud
  • psql, pour créer la base de données. Vous pouvez également exécuter le statement CREATE DATABASE dans la console SQL.

Créer un service ClickHouse Managed Postgres

Dans la console ClickHouse Cloud, cliquez sur New service et sélectionnez Postgres. L’instance est prête en quelques minutes. Pour une présentation pas à pas, consultez le guide de démarrage rapide.

Obtenir vos informations de connexion

Cliquez sur Connect dans la barre latérale gauche de votre service. La fenêtre modale affiche votre nom d’utilisateur, votre mot de passe, le serveur et le port, ainsi qu’un sélecteur Directly / via PgBouncer. Une fois Directly sélectionné, activez Use SSL et ouvrez l’onglet jdbc. Celui-ci affiche une URL JDBC utilisable dans Spring Boot moyennant deux modifications, que vous effectuerez dans la section Configurer la connexion : le nom de la base de données et le nom du fichier du certificat de CA.
L’URL JDBC ne contient ni le nom d’utilisateur ni le mot de passe : Spring Boot les lit à partir de propriétés distinctes. Ce guide se connecte directement à Postgres sur le port 5432. Une application Spring Boot est un processus de longue durée qui gère son propre pool HikariCP (10 connexions par défaut) ; elle n’a donc pas besoin d’un second pooler devant Postgres. Veillez à ce que le nombre d’instances de l’application multiplié par la taille du pool reste inférieur à la valeur max_connections du service. Si vous exécutez de nombreuses instances, consultez Utiliser PgBouncer. Dans la fenêtre modale, cliquez sur Download CA certificate. Vous pouvez également le télécharger depuis Settings → CA Certificate. Ce certificat étant propre à votre instance, le driver peut s’en servir pour vérifier qu’il communique bien avec votre serveur.

Configurer le projet

Générez un projet Maven avec Spring Initializr en ajoutant les dépendances Spring Web, Spring Data JPA, Flyway Migration et PostgreSQL Driver :
Vous partez d’une application existante ?Ignorez la commande curl. Dans votre fichier pom.xml, ajoutez les dépendances spring-boot-starter-data-jpa, spring-boot-starter-flyway et org.flywaydb:flyway-database-postgresql, ainsi que org.postgresql:postgresql avec le scope runtime, puis supprimez com.h2database:h2 si votre application utilise H2. Passez ensuite à la section Configurer la connexion.

Configurer la connexion

Déplacez le certificat de CA que vous avez téléchargé dans le répertoire du projet, puis renommez-le en ca-certificate.pem. Créez une base de données pour l’application. Remplacez <PASSWORD> et l’hôte par les valeurs affichées dans la fenêtre modale Connect :
Remplacez le contenu de src/main/resources/application.properties par ce qui suit. Dans une application existante, ajoutez les lignes spring.datasource et spring.jpa, puis supprimez tout autre paramètre spring.datasource, par exemple une URL H2. Il s’agit de l’URL de l’onglet jdbc, en remplaçant la base de données par guide_spring et en faisant pointer sslrootcert vers le fichier renommé :
src/main/resources/application.properties
pgjdbc lit sslmode=verify-full et sslrootcert dans l’URL. Il charge chaque certificat du fichier de CA et vérifie à la fois la chaîne de certificats et le nom d’hôte : vous n’avez donc besoin d’aucun code TLS supplémentaire. Spring Boot lit le mot de passe dans la variable d’environnement DATABASE_PASSWORD, si bien qu’il n’apparaît pas dans le fichier. Les autres paramètres :
  • ddl-auto=validate indique à Hibernate de vérifier au démarrage que vos entités correspondent aux tables créées par Flyway. Hibernate ne modifie pas le schéma.
  • open-in-view=false restitue chaque connexion au pool dès la fin de sa transaction, au lieu de la conserver jusqu’à l’écriture de la réponse HTTP.
Un path sslrootcert relatif est résolu par rapport au répertoire de travail de la JVM. ./mvnw spring-boot:run démarre l’application dans le répertoire du projet : ca-certificate.pem y est donc trouvé. Si vous exécutez le JAR empaqueté depuis un autre emplacement, utilisez un path absolu. pgjdbc ne développe pas ~.Si vous copiez l’URL avec Use SSL désactivé, elle ne contient pas de sslmode et pgjdbc utilise alors prefer : il chiffre la connexion, mais ne vérifie pas le serveur. Si la CA est incorrecte, la connexion échoue avec PKIX path building failed. Si le fichier est introuvable, elle échoue avec Could not open SSL root certificate file. Si l’hôte ne correspond pas au certificat, par exemple lorsque vous vous connectez via une adresse IP, elle échoue avec The hostname ... could not be verified by hostnameverifier PgjdbcHostnameVerifier.

Créer la table avec Flyway

Au démarrage de l’application, Flyway exécute les fichiers SQL situés dans src/main/resources/db/migration dans l’ordre de leurs versions, avant que Hibernate ne valide le schéma. Créez le fichier src/main/resources/db/migration/V1__create_todos.sql :
src/main/resources/db/migration/V1__create_todos.sql
Flyway enregistre chaque fichier appliqué dans la table flyway_schema_history et n’exécute que les nouveaux fichiers lors des démarrages suivants. Pour modifier le schéma, ajoutez un nouveau fichier, par exemple V2__add_due_date.sql, plutôt que de modifier un fichier déjà exécuté.
Une application qui utilisait H2 laissait généralement Hibernate créer ses tables, car ddl-auto vaut par défaut create-drop pour les bases de données embarquées. Pour Postgres, la valeur par défaut est none : ajoutez donc une migration qui crée vos tables existantes. Un @Id associé à un simple @GeneratedValue nécessite également une séquence nommée d’après l’entité, par exemple employee_seq pour Employee, avec un incrément de 50, soit la taille d’allocation par défaut d’Hibernate. À défaut, le démarrage échoue avec l’erreur Schema validation: missing sequence [employee_seq], ou avec The increment size of the [employee_seq] sequence is set to [50] in the entity mapping but the mapped database sequence increment size is [1] si la séquence s’incrémente de 1 :

Interroger la base de données

Créez l’entité dans src/main/java/com/example/todos/Todo.java. Spring Boot mappe le champ createdAt sur la colonne created_at :
src/main/java/com/example/todos/Todo.java
Créez un repository Spring Data dans src/main/java/com/example/todos/TodoRepository.java. Spring Data se charge d’implémenter l’interface au moment de l’exécution :
src/main/java/com/example/todos/TodoRepository.java
Créez un contrôleur REST dans src/main/java/com/example/todos/TodoController.java, avec un seul appel au repository par route :
src/main/java/com/example/todos/TodoController.java
Chaque appel au repository s’exécute dans sa propre transaction, sur une connexion issue du pool HikariCP. Pour regrouper plusieurs appels dans une même transaction, placez-les dans une méthode annotée avec @Transactional.

Exécuter et vérifier

Définissez le mot de passe et lancez l’application :
Au premier démarrage, Flyway applique la migration avant que le serveur web ne démarre. Le journal contient les lignes suivantes, reproduites ici sans les timestamp ni les noms de threads :
Dans un second terminal, créez deux tâches, marquez la première comme terminée, puis supprimez la seconde :
Les requêtes POST renvoient les nouvelles lignes et la requête PATCH renvoie la ligne mise à jour. L’option -w '\n' ajoute un saut de ligne après chaque réponse :
Ouvrez http://localhost:3113/todos dans votre navigateur pour afficher la liste des tâches restantes. La réponse se présente comme suit :
Pour vérifier que les connexions de l’application utilisent TLS, interrogez pg_stat_ssl pendant que l’application s’exécute :
Les 10 connexions correspondent au pool HikariCP. Arrêtez l’application avec Ctrl+C. Pour consulter les données dans la console, ouvrez console SQL dans la barre latérale gauche de votre service, développez guide_spring puis public, et cliquez sur la table todos. La table flyway_schema_history, juste à côté, contient l’historique des migrations. La table todos contient la ligne restante :

Utiliser PgBouncer

Lorsque l’ensemble des instances de l’application approche de la limite de connexions Postgres, connectez l’application via le PgBouncer intégré, sur le port 6432, et conservez la connexion directe pour Flyway. Dans application.properties, remplacez le port dans spring.datasource.url par 6432, puis ajoutez en dessous les lignes spring.flyway suivantes :
src/main/resources/application.properties
Lorsque spring.flyway.url est défini, Flyway ouvre sa propre connexion et n’utilise pas le nom d’utilisateur ni le mot de passe de spring.datasource. Définissez donc également spring.flyway.user et spring.flyway.password. Le même certificat de CA fonctionne pour les deux ports. PgBouncer fonctionne en mode pool de connexions par transaction : chaque transaction peut donc s’exécuter sur une connexion Postgres différente. Avec Spring Boot :
  • Les requêtes préparées fonctionnent avec les paramètres par défaut du driver ; vous n’avez donc pas besoin de prepareThreshold=0. À partir de la cinquième exécution d’un statement sur une connexion (prepareThreshold), pgjdbc utilise une requête préparée nommée côté serveur. Il libère les statements à l’aide d’un message Close au niveau du protocole, que le PgBouncer fourni prend en charge.
  • pgjdbc 42.7.5 ou version ultérieure est obligatoire. Les versions plus anciennes envoient le paramètre de démarrage extra_float_digits, et PgBouncer rejette alors la connexion avec FATAL: unsupported startup parameter: extra_float_digits. Spring Boot 4 embarque une version plus récente de pgjdbc. Avec les versions antérieures de Spring Boot, définissez <postgresql.version>42.7.13</postgresql.version> dans la section <properties> de pom.xml.
  • Les paramètres de session ne sont pas conservés. Les statements SET et Connection.setSchema (utilisé par la propriété spring.datasource.hikari.schema de HikariCP) ne s’appliquent qu’à la connexion Postgres qui les exécute, et peuvent déborder sur d’autres clients. Les paramètres d’URL currentSchema et options échouent avec FATAL: unsupported startup parameter. Utilisez des noms de tables qualifiés par le schéma, ou SET LOCAL à l’intérieur d’une transaction.
  • Flyway fonctionne par défaut via PgBouncer, car il acquiert un verrou consultatif (advisory lock) au niveau de la transaction. Les migrations qui exécutent CREATE INDEX CONCURRENTLY nécessitent spring.flyway.postgresql.transactional-lock=false, ce qui fait basculer Flyway sur un verrou au niveau de la session. Via PgBouncer, ce verrou échoue avec Unable to release PostgreSQL advisory lock et reste détenu sur une connexion du pool ; utilisez donc la connexion directe pour Flyway.
  • Taille du pool : chaque connexion HikariCP est une connexion client peu coûteuse vers PgBouncer. PgBouncer limite le nombre de connexions Postgres qu’il ouvre pour chaque base de données et chaque utilisateur (default_pool_size), quel que soit le nombre de connexions client ouvertes par les instances de votre application. Les transactions au-delà de cette limite patientent dans PgBouncer jusqu’à query_wait_timeout (120 secondes par défaut) au lieu d’échouer dans HikariCP. Agrandir le pool HikariCP n’augmente la concurrence que dans la limite de cette valeur ; la valeur par défaut de 10 par instance constitue donc un bon point de départ. Consultez PgBouncer et limites de connexions Postgres.
pg_stat_ssl rend compte de la connexion entre PgBouncer et Postgres ; la requête TLS de la section Exécuter et vérifier n’affiche donc pas les connexions de l’application passant par PgBouncer. La connexion de l’application à PgBouncer est néanmoins bien vérifiée : un certificat de CA incorrect provoque le même échec.

Prochaines étapes

  • Connexion : chaînes de connexion, PgBouncer et TLS
  • Paramètres : paramètres de Postgres et de PgBouncer, comme max_connections
  • Répliques en lecture : envoyer des requêtes en lecture seule vers une réplique
  • Sécurité : listes d’accès IP et réseau privé