I love Liquibase

Ciao Developer, in questo articolo ti presento una libreria open source che uso regolarmente e che considero molto utile: Liquibase.

Come spesso accade, ogni cliente simpatizza per Mysql o SqlServer, Oracle e chi più ne ha più ne metta, ma non è sempre sostenibile rendere l’applicazione scalabile su più database.
In passato, per esempio, ho riscontrato due grandi difficoltà in alcuni progetti:

  • Le query sql: lavorando con entity framework riesci in qualche modo a cavartela;
  • Script create table e update: qui arriva il bello, ti ritrovi con script per ogni tipo di database, ed è qui che a mio parere Liquibase compie il miracolo.

Che cos’è e cosa fa? Liquibase è una libreria open source indipendente dal database per tracciare, gestire e applicare le modifiche allo schema del database.

In che senso? Devo comunque scrivere degli script? Sì, il tutto si traduce in un progetto Maven e un insieme di files XML 😀 (non è l’unico ma supporta anche JSON, YAML e altro)

Bando alle ciance e iniziamo a lavorare.

Anatomia del progetto

Per prima cosa creiamo il progetto Maven e lo apriamo con VSC:

$> mvn archetype:generate -DgroupId=it.lbonaldo -DartifactId=liquibase-example 
       -DarchetypeArtifactId=maven-archetype-quickstart 
       -DinteractiveMode=false
$> cd liquibase-example
$> code .

Ultimamente simpatizzo per VSC (Visual Studio Code) ma potete usare qualsiasi editor o IDE che preferite.

Fatta pulizia preferisco dividere gli script in due directory:

  • changelog: ogni script contenuto rappresenta una modifica alla struttura del database (create table, alter column ecc..);
  • seed: ogni script contenuto lo scopo di valorizzare o aggiornare le tabelle;
  • db-changelog-master.xml: file generale che raggruppa e referenzia gli script contenuti nelle directory precedenti;
  • pom.xml: file di progetto Maven

Apriamo il file pom.xml e aggiungiamo il plugin Liquibase, i driver del database e dei profili di esecuzione dello script:

...
  <build>
    <plugins>
      <plugin>
        <groupId>org.liquibase</groupId>
        <artifactId>liquibase-maven-plugin</artifactId>
        <version>3.5.3</version>
        <configuration>
          <driver>${liquibase.driver}</driver>
          <url>${liquibase.url}</url>
          <username>${liquibase.username}</username>
          <password>${liquibase.password}</password>
          <changeLogFile>db-changelog-master.xml</changeLogFile>
          <promptOnNonLocalDatabase>false</promptOnNonLocalDatabase>
          <verbose>true</verbose>
          <contexts>${liquibase.contexts}</contexts>
        </configuration>
      </plugin>
    </plugins>
  </build>

  <profiles>
    <profile>
      <id>dev_mysql</id>
      <activation>
        <activeByDefault>true</activeByDefault>
      </activation>
      <properties>
        <liquibase.url>jdbc:mysql://localhost:3306/test</liquibase.url>
        <liquibase.driver>org.mariadb.jdbc.Driver</liquibase.driver>
        <liquibase.username>****</liquibase.username>
        <liquibase.password>****</liquibase.password>
        <liquibase.contexts>!test</liquibase.contexts>
      </properties>
    </profile>
  </profiles>

  <dependencies>
    <dependency>
      <groupId>org.mariadb.jdbc</groupId>
      <artifactId>mariadb-java-client</artifactId>
      <version>2.4.1</version>
    </dependency>
  </dependencies>
...

Nota che il plugin si aspetta da configurazione il file change log file che nel nostro caso corrisponde al db-changelog-master.xml (vedremo in seguito a cosa serve). Il resto dei parametri di configurazione verranno letti runtime dal profilo di esecuzione.

Per eseguire Liquibase basta lanciare il comando, dove il parametro –P rappresenta il profilo di esecuzione:

$> mvn liquibase:update -P<nome profilo>
// Esempio: mvn liquibase:update -Pdev_mysql

In questo esempio sto usando MySql come database di riferimento ma nulla vieta di aggiungere altri driver e profili specifici per ogni database (Esempio: aggiungo i driver PostgreSql e un nuovo profilo che chiamerò con molta fantasia dev_psql).
Se tutto è andato a buon fine oltre alle nostre tabelle, Liquibase ne crea due di servizio per gestire e tracciare tutte le modifiche apportate nel tempo al database:

Liqui base tabelle di servizio
  • DATABASECHANGELOG: In questa tabella vengono tracciati tutti i changesets lanciati nel tempo (vedremo in seguito che sono istruzioni contenute nei file chengelog);
  • DATABASECHANGELOGLOCK: Liquibase utilizza questa tabella per garantire che sia in esecuzione solo un’istanza di Liquibase alla volta.

Changesets

Questa parola chiave introdotta a metà articolo rappresenta il concetto fondamentale di aggiornamento del database. Infatti, i changesets sono istruzioni scritte nei files di changelogs (ricordate changelog e seed) che permettono le modifiche al database.

Prendiamo come esempio il file changelog/db-changelog-1.0.xml:

<databaseChangeLog ... >

	<changeSet id="1.0-c" author="lbonaldo">

		<createTable tableName="customer">
			<column name="id" type="bigint" autoIncrement="true">
				<constraints primaryKey="true" nullable="false" />
			</column>
			<column name="nickname" type="varchar(256)">
				<constraints nullable="false" unique="true" />
			</column>
			<column name="firstname" type="varchar(256)" />
			<column name="lastname" type="varchar(256)" />
			<column name="age" type="smallint" />
			<column name="ts_ins" type="datetime" defaultValue="now()">
				<constraints nullable="false" />
			</column>
			<column name="ts_mod" type="datetime" />
		</createTable>

	</changeSet>

</databaseChangeLog>

Come potete intuire ogni changeset contiene una o più istruzioni SQL, in questo esempio stiamo creando la tabella customer. Ogni tag ha il suo specifico compito.

Nel mio esempio gli script Liquibase, in serie, eseguono la seguente logica descritta nel file db-changelog-master.xml (che ricordo essere il file dato in pasto a Liquibase in configurazione):

<databaseChangeLog ...>

	<include file="changelog/db-changelog-1.0.xml" />
	<include file="seed/db-seed-1.0.xml" />
	<include file="changelog/db-changelog-1.1.xml" />
	<include file="seed/db-seed-1.1.xml" />

</databaseChangeLog>
  1. changelog-1.0: crea la tabella customer;
  2. seed-1.0: inserisce tre record nella tabella customer;
  3. changelog-1.1: aggiunge una colonna alla tabella customer;
  4. seed-1.1: aggiorna un record della tabella customer.

Conclusione

Spero di esserti stato d’aiuto con questo breve e semplice tutorial, ora tocca a voi studiare per bene la documentazione ufficiale di Liquibase e iniziare ad usarlo nei vostri progetti.

Se siete a conoscenza di librerie o metodi alternativi per gestire le modifiche al database, per favore scrivetemi o lasciate un commento, grazie.
C’è sempre qualcosa di nuovo da imparare!

Scarica l’esempio completo: https://Bonny@bitbucket.org/Bonny/liquibase-example.git

Leggi anche Strutture dati o selettive?

Sito ufficiale Liquibase: https://www.liquibase.org/

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

sedici + 15 =