Using the Liquibase Java API

Liquibase has an option to be set and run automatically on startup:

  • For web applications that use continuous delivery and have an automated release process from code check-in through live production which gets executed multiple times per day
  • In packaged applications that are shipped to make the database management portion transparent

Once Liquibase is set to run automatically on startup, your database state always matches what your code expects, and you have no manual steps to forget. This method works best in environments where you have less control over the deployment process or want a simpler deployment process.

Liquibase uses a DATABASECHANGELOGLOCK table to ensure that only one instance of Liquibase runs at a time in case you have multiple servers pointing to the same database. Even if you have a cluster of servers all coming online at the same time and all automatically running Liquibase, the DATABASECHANGELOGLOCK table will ensure that they will not update the database concurrently and cause problems.

Liquibase ships with two hooks to automatically update your database on startup: Servlet Listener and Spring Bean. However, you can also call the Liquibase Java API directly.

The most straightforward way of directly running Liquibase looks as follows:

  1. Import the Liquibase API.

  2. The Liquibase API is packaged in the liquibase-core.jar file that you need to include in your classpath. Download the liquibase-core.jar file at the Maven Repository for Liquibase page and add it to your project. The Maven page presents different versions with the examples for various build systems.

  1. Create a text file in your application directory and name it changelog.sql. Liquibase also supports the .xml, .yaml, or .json changelog formats.
  2. Liquibase uses a changelog file to sequentially list all changes made to your database. It looks for changelog files in your application’s classpath. Thus, put your changelog file in a location that will be compiled into your application. For example, if you use a standard Maven project, create a file in src/main/resources.

  1. Add changesets to your changelog file. Use the following examples depending on the format of the changelog you created:
  1. Use the Liquibase API.
  • Configure and manage global configuration settings. The Liquibase API includes a liquibase.Scope object, which allows you to control the scope for all settings. The Scope.child() function takes the settings that apply within the given function, and when that function exits, the configured settings are dropped out of scope.
  • Map<String, Object> config = new HashMap<>();
    //add values to the config
    Scope.child(config, () -> {
        //Liquibase calls will go here
    });

    For example, you can configure the Liquibase Pro key as follows:

    Map<String, Object> config = new HashMap<>();
    config.put("liquibase.pro.licenseKey", "YOUR_PRO_KEY");
    
    Scope.child(config, () -> {
    //Liquibase calls will go here
    });

    Everything running within the Scope.child(config, () -> { //Liquibase calls will go here }); Lambda function will use the configured Liquibase Pro key.

  • Configure the liquibase.Liquibase façade using the Lambda function and creating the liquibase object that takes the reference to your changelog file, a liquibase.resource.ResourceAccessor implementation, and a liquibase.database.Datababase object:

  • Map<String, Object> config = new HashMap<>();
    config.put("liquibase.pro.licenseKey", "YOUR_PRO_KEY");
    
    Scope.child(config, () -> {
      Connection connection = openConnection(); //your openConnection logic 
      
      Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection));
      
      Liquibase liquibase = new liquibase.Liquibase("path/to/changelog.sql", new ClassLoaderResourceAccessor(), database);
    
      //Liquibase calls will go here
    });

    Note: Replace the openConnection() method with the method your application takes to get a connection to your database. The information can often be pulled from a connection pool.

  • Once you have your liquibase object created, call the business logic methods on it. For example:
  • Map<String, Object> config = new HashMap<>();
    config.put("liquibase.pro.licenseKey", "YOUR_PRO_KEY");
    
    Scope.child(config, () -> {
     
      Connection connection = openConnection(); //your openConnection logic 
    
      Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection));
    
      Liquibase liquibase = new liquibase.Liquibase("path/to/changelog.sql", new ClassLoaderResourceAccessor(), database);
    
      liquibase.update(new Contexts(), new LabelExpression());
    });

    The command will perform an update operation with the changelog and database passed to the Liquibase constructor. Instead of the update operation, you can call any other functions on the Liquibase object, such as rollback(), reportStatus(), and others.

    Tip: The liquibase.update() function requires the contexts and labels objects to be specified. The example uses an empty context and label setup, so the actual execution will not take any labels or contexts into account.

For more detailed information, check the Liquibase API documentation.

Related links