Using Liquibase with Hibernate

Image of Julius Krah Written by: Julius Krah

The purpose of this document is to guide you through the process of creating a new Liquibase project and integrating it into your Hibernate ORM setup. In this tutorial you will learn how to install the required database drivers and configure the liquibase.properties file to establish a database connection to a H2 database.

Prerequisites

  • Ensure that you have installed the latest version of Liquibase. If not, go to https://www.liquibase.org/download to install it. Find the appropriate executable for your platform
  • Ensure that the Liquibase executable location is in the PATH environment variable.

Note: We will refer to the location of the Liquibase executable as $LIQUIBASE_HOME in this tutorial.

Tutorial

We will be creating a Maven project for this tutorial. To configure a Liquibase project for Hibernate, perform the following steps:

  1. Install the Liquibase extension by copying the extension jar file into the $LIQUIBASE_HOME/lib directory.
  2. Create a project folder and name it HibernateLiquibase. The project folder will be used to store the Liquibase configuration files and changelogs.
  3. Create a liquibase.properties file and place it in your src/main/resources directory.
  4. Note: If you are not familiar with configuring the liquibase.properties file, review this tutorial:Creating and configuring a liquibase.properties file.

    The liquibase.properties file should contain the following properties:

    changeLogFile=dbchangelog.xml
    url=hibernate:ejb3:com.liquibase.hibernate.tutorial.jpa
    driver=liquibase.ext.hibernate.database.connection.HibernateDriver
    classpath=target\\hibernate-liquibase-0.0.1-SNAPSHOT.jar

    Note: Liquibase supports only the following special characters in passwords~ # $ % * ( ) - _ + [ ] { } . ?. Unsupported special characters are as follows: @ & / : < > " ' ` | ^ ! = , \ <spaces>.

    • If you placed your jar files in the Liquibase/lib install directory, there is no need to specify the classpath property in the liquibase.properties file. Otherwise, put the path to your drivers as it is shown in the preceding example.
    • If you have a Liquibase Pro key and want to apply it to your project, add the following property to your liquibase.properties file:
    • liquibaseProLicenseKey: <paste license key>
  5. Create a pom.xml file in the HibernateLiquibase folder and add the following content in the file:
  6. <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    	<modelVersion>4.0.0</modelVersion>
    
    	<groupId>com.liquibase</groupId>
    	<artifactId>hibernate-liquibase</artifactId>
    	<version>0.0.1-SNAPSHOT</version>
    	<packaging>jar</packaging>
    
    	<name>Liquibase Hibernate Example</name>
    	<description>Demo project for liquibase and hibernate</description>
    
    		<properties>
    			<liquibase.version>3.10.2</liquibase.version>
    			<liquibase-hibernate5.version>3.10.2</liquibase-hibernate5.version>
    			<javassist.version>3.24.0-GA</javassist.version>
    			<validation-api.version>2.0.1.Final</validation-api.version>
    			<maven.build.timestamp.format>yyyyMMddHHmmss</maven.build.timestamp.format>
    			<spring-boot.version>2.3.4.RELEASE</spring-boot.version>
    			<hibernate5.version>5.4.21.Final</hibernate5.version>
    			<maven.compiler.source>11</maven.compiler.source>
    			<maven.compiler.target>11</maven.compiler.target>
    			<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    		</properties>
    
    		<dependencies>
    			<dependency>
    				<groupId>org.hibernate</groupId>
    				<artifactId>hibernate-core</artifactId>
    				<version>${hibernate5.version}</version>
    			</dependency>
    			<dependency>
    				<groupId>com.h2database</groupId>
    				<artifactId>h2</artifactId>
    				<version>1.4.200</version>
    			</dependency>
    		</dependencies>
    
    	<build>
    		<plugins>
    			<plugin>
    				<groupId>org.codehaus.mojo</groupId>
    				<artifactId>exec-maven-plugin</artifactId>
    				<version>3.0.0</version>
    				<configuration>
    					<executable>java</executable>
    					<arguments>
    						<argument>-classpath</argument>
    						<classpath/>
    						<argument>com.liquibase.Application</argument>
    					</arguments>
    				</configuration>
    			</plugin>
    			<plugin>
    				<groupId>org.liquibase</groupId>
    				<artifactId>liquibase-maven-plugin</artifactId>
    				<version>${liquibase.version}</version>
    				<configuration>
    					<changeLogFile>${project.basedir}/src/main/resources/config/liquibase/master.xml</changeLogFile>
    					<outputChangeLogFile>dbchangelog.xml</outputChangeLogFile>
    					<diffChangeLogFile>${project.basedir}/src/main/resources/db/migrations/${maven.build.timestamp}_changelog.xml</diffChangeLogFile>                   
    					<propertyFile>liquibase.properties</propertyFile>
    					<logging>debug</logging>
    					<contexts>!test</contexts>
    				</configuration>
    				<dependencies>
    					<dependency>
    						<groupId>org.liquibase</groupId>
    						<artifactId>liquibase-core</artifactId>
    						<version>${liquibase.version}</version>
    					</dependency>
    					<dependency>
    						<groupId>org.liquibase.ext</groupId>
    						<artifactId>liquibase-hibernate5</artifactId>
    						<version>${liquibase-hibernate5.version}</version>
    					</dependency>
    					<dependency>
    						<groupId>org.springframework.boot</groupId>
    						<artifactId>spring-boot-starter-data-jpa</artifactId>
    					<version>${spring-boot.version}</version> 
    				 </dependency>
    					<dependency> 
    						<groupId>javax.validation</groupId>
    						<artifactId>validation-api</artifactId>  
    						<version>${validation-api.version}</version> 
    					</dependency>
    					<dependency>
     						<groupId>org.javassist</groupId>
    						<artifactId>javassist</artifactId>
    						<version>${javassist.version}</version>
    					</dependency>
    				</dependencies>
    			</plugin>
    		</plugins>
    	</build>
    </project>
  7. Get the additional dependencies by running the following command from the same directory as the pom.xml file:
  8. mvn dependency:copy-dependencies -DoutputDirectory=${project.build.directory}/lib -Dhttps.protocols=TLSv1.2

    Copy the following jars from ./target/lib to $LIQUIBASE_HOME/lib:

    • byte-buddy-1.10.10.jar
    • classmate-1.5.1.jar
    • dom4j-2.1.3.jar
    • hibernate-commons-annotations-5.1.0.Final.jar
    • hibernate-core-5.4.21.Final.jar
    • jandex-2.1.3.Final.jar
    • javax.persistence-api-2.2.jar
    • jboss-logging-3.3.2.Final.jar
    • jboss-transaction-api_1.2_spec-1.1.1.Final.jar
  9. Create a JPA configuration file at META-INF/persistence.xml. The persistence.xml file should be placed in with the following content:
  10. <persistence xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0">
    	<persistence-unit name="com.liquibase.hibernate.tutorial.jpa" transaction-type="RESOURCE_LOCAL">
    		<properties>
    			<property name="javax.persistence.schema-generation.database.action" value="none" />
    			<property name="javax.persistence.provider" value="org.hibernate.jpa.HibernatePersistenceProvider" />
    			<property name="javax.persistence.jdbc.driver" value="org.h2.Driver" />
    			<property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://localhost:9090/mem:dev" />
    			<property name="javax.persistence.jdbc.user" value="dbuser" />
    			<property name="javax.persistence.jdbc.password" value="letmein" />
    			<property name="hibernate.connection.handling_mode" value="delayed_acquisition_and_release_after_transaction" />
    		</properties>
    	</persistence-unit>
    </persistence>
  11. Create entity classes by using your favorite text editor and creating the folder src/main/java/com/liquibase. In this directory, create a file House.java and add the following content:
  12. package com.liquibase;
    	
    	import java.io.Serializable;
    	import javax.persistence.*;
    	@Entity
    	public class House implements Serializable {
    		private static final long serialVersionUID = 1L;
    		@Id
    		@GeneratedValue
    		private Integer id;
    		private String owner;
    		private boolean fullyPaid;
    	
    		public Integer getId() {
    		return id;
    		}
    	
    		public void setId(Integer id) {
    		this.id = id;
    		}
    	
    		public String getOwner() {
    		return owner;
    		}
    	
    		public void setOwner(String owner) {
    		this.owner = owner;
    		}
    	
    		public boolean isFullyPaid() {
    		return fullyPaid;
    		}
    	
    		public void setFullyPaid(boolean fullyPaid) {
    		this.fullyPaid = fullyPaid;
    		}
    	
    	}
    
  13. Create a second file Item.java in the same directory and paste the following:
  14. package com.liquibase;
                
    	import java.io.Serializable;
        import javax.persistence.*;
        @Entity
        public class Item implements Serializable {
        	private static final long serialVersionUID = 1L;
            @Id
            @GeneratedValue
            private Integer id;
            private String name;
            @ManyToOne
            private House house;
    
            public Integer getId() {
            	return id;
            }
    
            public void setId(Integer id) {
            this.id = id;
            }
    
            public String getName() {
            return name;
            }
    
            public void setName(String name) {
            this.name = name;
            }
    
    		public House getHouse() {
    		return house;
    		}
    
    		public void setHouse(House house) {
    		this.house = house;
    		}
    
    	}
  15. Generate a dbchangelog.xml file from hibernate in the project folder. If you haven't already, first install the application using the mvnw install command.
  16. The generated jar is what is referenced in the liquibase.properties file

    classpath=target\\hibernate-liquibase-0.0.1-SNAPSHOT.jar

    Next, generate the dbchangelog.xml file

    liquibase --logLevel=INFO --defaultsFile=src/main/resources/liquibase.properties generateChangeLog
  17. Verify the project configuration by running the Liquibase status command to verify that the configuration is complete.
  18. Open a command prompt and navigate to the project folder. Run the command as shown below:

    [liquibase@ip-172-30-3-94 dbtest]$ liquibase --logLevel=INFO --defaultsFile=src/main/resources/spring.properties status

    Example Output

    Liquibase Community 3.10.2 by Datical
    ####################################################
    ##   _     _             _ _                      ##
    ##  | |   (_)           (_) |                     ##
    ##  | |    _  __ _ _   _ _| |__   __ _ ___  ___   ##
    ##  | |   | |/ _` | | | | | '_ \ / _` / __|/ _ \  ##
    ##  | |___| | (_| | |_| | | |_) | (_| \__ \  __/  ##
    ##  \_____/_|\__, |\__,_|_|_.__/ \__,_|___/\___|  ##
    ##              | |                               ##
    ##              |_|                               ##
    ##                                                ##
    ##  Get documentation at docs.liquibase.com       ##
    ##  Get certified courses at learn.liquibase.com  ##
    ##  Get advanced features and support at          ##
    ##      liquibase.com/protrial                    ##
    ##                                                ##
    ####################################################
    Starting Liquibase at Fri, 04 Sep 2020 19:53:36 UTC (version 3.10.2 #22 built at Mon Jul 27 04:21:02 UTC 2020)
    Liquibase command 'status' was executed successfully.
    
  19. Verify that the DATABASECHANGELOG and DATABASECHANGELOGLOCK tables were created.
  20. Using a database UI tool, you should see the new Liquibase tables.

    DATABASECHANGELOG tracking table. This table keeps a record of all the changesets that were deployed. When you run Liquibase update, the changesets in the changelog will be compared with the DATABASECHANGELOG tracking table and only the new changesets that were not found in the DATABASECHANGELOG will be deployed.

    DATABASECHANGELOGLOCK tracking table. This table is used internally by Liquibase to manage access to the changelog table during deployment.

Congratulations!

You have successfully configured your project and can begin creating changesets to migrate changes to your database using Hibernate

Next steps: changeset

Source code is available at: https://github.com/juliuskrah/hibernate-liquibase

See also