Migrations de bases de données en Kotlin : comment gérer le schéma sans douleur
\nLors du développement en Kotlin, surtout en combinaison avec la JVM, tôt ou tard se pose le problème de la synchronisation de la structure de la base de données entre les développeurs, les serveurs de test et de production. L'exécution manuelle de scripts SQL entraîne une désynchronisation et des erreurs. La solution — les migrations de bases de données. C'est une méthode automatisée pour versionner les modifications du schéma : création de tables, ajout de colonnes, d'index et de déclencheurs.
\nDans cet article, nous analyserons trois outils populaires pour Kotlin : Flyway, Liquibase et le mécanisme intégré Exposed. Vous apprendrez comment les intégrer dans un projet, écrire des migrations et éviter les problèmes typiques.
\n\nFlyway : simplicité et versionnement
\nFlyway est l'outil de migration le plus populaire dans l'écosystème JVM. Il prend en charge Kotlin, Java et Groovy. Principe de fonctionnement : vous écrivez des scripts SQL (ou des classes Java/Kotlin), et Flyway suit ceux qui ont déjà été appliqués à l'aide de la table flyway_schema_history.
Connexion dans Gradle (Kotlin DSL) :
\ndependencies {\n implementation("org.flywaydb:flyway-core:9.22.3")\n // pour PostgreSQL\n implementation("org.flywaydb:flyway-database-postgresql:9.22.3")\n}\nExemple de migration V1__create_users.sql :
CREATE TABLE users (\n id SERIAL PRIMARY KEY,\n username VARCHAR(50) NOT NULL UNIQUE,\n email VARCHAR(100) NOT NULL,\n created_at TIMESTAMP DEFAULT NOW()\n);\n\nCREATE INDEX idx_users_email ON users(email);\nLancement depuis le code Kotlin :
\nimport org.flywaydb.core.Flyway\n\nfun main() {\n val flyway = Flyway.configure()\n .dataSource("jdbc:postgresql://localhost:5432/mydb", "user", "pass")\n .load()\n flyway.migrate()\n}\nAvantages :
\n- \n
- Configuration minimale \n
- Prise en charge des rollbacks (undo) dans la version payante \n
- Fonctionne avec n'importe quel SQL \n
Inconvénients :
\n- \n
- Pas de validation intégrée du schéma \n
- Gestion difficile des branches \n
Liquibase : flexibilité et déclarativité
\nLiquibase propose deux approches : les modifications peuvent être décrites en XML, YAML, JSON ou directement en SQL. Pour les projets Kotlin, le format YAML est pratique — il est lisible et facile à versionner.
\nAjout dans Gradle :
\ndependencies {\n implementation("org.liquibase:liquibase-core:4.24.0")\n}\nExemple de fichier changelog db.changelog-master.yaml :
databaseChangeLog:\n - changeSet:\n id: 1\n author: developer\n changes:\n - createTable:\n tableName: users\n columns:\n - column:\n name: id\n type: BIGINT\n autoIncrement: true\n constraints:\n primaryKey: true\n - column:\n name: username\n type: VARCHAR(50)\n constraints:\n nullable: false\n unique: true\n - column:\n name: email\n type: VARCHAR(100)\n - createIndex:\n indexName: idx_users_email\n tableName: users\n columns:\n - column:\n name: email\nLancement depuis Kotlin :
\nimport liquibase.Liquibase\nimport liquibase.database.jvm.JdbcConnection\nimport liquibase.resource.ClassLoaderResourceAccessor\nimport java.sql.DriverManager\n\nfun runMigrations() {\n val connection = DriverManager.getConnection(\n "jdbc:postgresql://localhost:5432/mydb", "user", "pass"\n )\n val database = DatabaseFactory.getInstance()\n .findCorrectDatabaseImplementation(JdbcConnection(connection))\n val liquibase = Liquibase("db.changelog-mas