Ecrire une migration Liquibase en Java


Liquibase est un outil très utile pour versionner sa base de données. La succession de refactoring à appliquer à une base peut-être décrite dans plusieurs formats de données (XML, YAML, JSON et SQL). Seulement il arrive qu’une migration soit “trop” complexe pour être décrite à partir des refactoring standards (ou alors tout simplement que l’on ne soit pas très à l’aise avec PL/SQL).
Dans ce cas on peut écrire un changement particulier en Java.

Implémenter un CustomChange

Liquibase propose deux interfaces pour créer son refactoring personnel, CustomTaskChange et CustomSqlChange. La première permet d’appliquer des changements qui ne génèrent pas de SQL contrairement à la seconde.
Cette dernière est à privilégier quand c’est possible puisque cela permet de sauvegarder le SQL généré dans un fichier (via un dryRun par exemple).

public class MyCustomChangeThatGenerateSql implements CustomSqlChange {

    @Override
    public SqlStatement[] generateStatements(final Database database) throws CustomChangeException {

        List<SqlStatement> statements = new ArrayList<>();
        
        JdbcConnection connection = (JdbcConnection) database.getConnection();
        try {
            ResultSet persons = connection.createStatement().executeQuery("select nom, prenom from person");
            while (persons.next()) {
                // Write your complex logic in here !
                // and generate SqlStatement(s)
            }
        } catch (DatabaseException | SQLException e) {
            throw new CustomChangeException(e);
        }
        
        SqlStatement insert = new InsertStatement(database.getDefaultCatalogName(), database.getDefaultSchemaName(), "person")
            .addColumnValue("nom", "Gay")
            .addColumnValue("prenom", "Jean-Christophe");
            
        SqlStatement update = new UpdateStatement(database.getDefaultCatalogName(), database.getDefaultSchemaName(), "person")
            .addNewColumnValue("prenom", "Jc")
            .setWhereClause(String.format("nom='%s'", Gay))
        
        statements.add(insert);
        statements.add(update);
            
        return statements.toArray(new SqlStatement[statements.size()]);
    }
    
    @Override
    public String getConfirmationMessage() {
        return null;
    }

    @Override
    public void setUp() throws SetupException {}

    @Override
    public void setFileOpener(ResourceAccessor resourceAccessor) {}

    @Override
    public ValidationErrors validate(Database database) {
        return null;
    }
}

La principale logique se passe dans la méthode generateStatements. L’API de Liquibase nous donne accès à la connexion Jdbc et il suffit de générer des SqlStatement pour décrire son refactoring.
Le reste des méthodes à implémenter permet de valider la configuration, accéder à des fichiers, etc. La Javadoc explique tout ça.

Configurer son changeset

L’élément customChange permet de déclarer la classe implémentant le refactoring.

<changeSet id="20140606-super-complex-change" author="jc.gay">
    <customChange class="fr.jcgay.MyCustomChangeThatGenerateSql" />
</changeSet>

Et voilà on peut décrire des changements complexes dans son langage préféré !


Voir également

comments powered by Disqus