Skip to content

A maven plugin and dependency to create complex migrations on persistent data using Hibernate and Flyway

License

Notifications You must be signed in to change notification settings

LarsBodewig/Hibernate-Based-Migration

Repository files navigation

Available on Maven Central

Hibernate-Based-Migration

Hibernate Based Migrations are a simple method to do complex migrations of persisted data using Hibernate. Since Hibernate mappings and annotated entity classes always represent the current state of the persisted data, the Maven plugin offers goals to freeze files in a specific version and thaw them in a later version to use in a Migration class. Hibernate Migrations leverage Flyway's rarely used Java-based-Migrations feature.

Usage

1. Add the hibernate-based-migration-plugin to your project

<plugin>
    <groupId>dev.bodewig.hibernate-based-migration</groupId>
    <artifactId>hibernate-based-migration-plugin</artifactId>
    <version>1.0.0</version>
</plugin>

2. Add the thaw goal to your project lifecycle

<plugin>
    ...
    <executions>
        <execution>
            <id>thaw</id>
            <goals>
                <goal>thaw</goal>
            </goals>
        </execution>
    </executions>
</plugin>

3. Add and execute the freeze goal to copy persistence files

<plugin>
    ...
    <executions>
        <execution>
            <id>freeze</id>
            <goals>
                <goal>freeze</goal>
            </goals>
            <configuration>
                <persistenceClassesFileList>
                    <file>src/main/java/dev/bodewig/hibernate_based_migration/example/Fruit.java</file>
                </persistenceClassesFileList>
                <persistenceResourcesFileList>
                    <file>src/main/resources</file>
                </persistenceResourcesFileList>
            </configuration>
        </execution>
    </executions>
</plugin>

4. Change your persistence files

@Entity
public class Fruit {
	@Id
	public String name;
	public int weight;
	public String colorHex; // --> public String colorRgb;
}

5. Call the freeze goal again (you now have 2 frozen versions)

src
|- main
|- migration
   |- 1
   |  |- java/...
   |  |- resources/...
   |- 2
      |- java/...
      |- resources/...

6. Add a dependency to hibernate-based-migration

<dependency>
    <groupId>dev.bodewig.hibernate-based-migration</groupId>
    <artifactId>hibernate-based-migration</artifactId>
    <version>1.0.0</version>
</dependency>

7. Subclass HibernateMigration to create a migration between the frozen versions of your persistence files (read the Hibernate configuration from the frozen version directories)

public class V1__My_Migration extends HibernateMigration {

	private List<OldData> persistedData;

	@Override
	protected long getSerialVersionUID() { ... }

	@Override
	public Configuration configBefore() {
		return new Configuration().configure("/_1/hibernate.cfg.xml");
	}

	@Override
	public Configuration configAfter() {
		return new Configuration().configure("/_2/hibernate.cfg.xml");
	}

	@Override
	public void doBefore(StatelessSession session) {
		this.persistedData = loadDataWithHibernate(session);
	}

	@Override
	public void doSql(Context context) throws SQLException {
		try (Statement stmt = context.getConnection().createStatement()) {
			// change your database scheme
		}
	}

	@Override
	public void doAfter(StatelessSession session) {
		NewData data = migrateData(this.persistedData);
		saveDataWithHibernate(data);
	}
}

8. Add the flyway-maven-plugin to your project

<plugin>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-maven-plugin</artifactId>
    <version>9.22.0</version>
</plugin>

9. Execute the migrate goal to run your migration class

<plugin>
    ...
    <executions>
        <execution>
            <id>migrate</id>
            <goals>
                <goal>migrate</goal>
            </goals>
        </execution>
    </executions>
</plugin>

10. Profit!

Your database scheme and your persisted data have been migrated - without doing complex value transformations in pure SQL.

A full example implementation is available in the hibernate-based-migration-example.

Hibernate-Based-Migration-Plugin Goals

Freeze (defaultPhase=GenerateSources,Execute=Compile)

Copy a set of files to a separate project directory, resolve the common package and place them in a versioned, named package.

Configuration option Description Default/Required Example
freezeVersion The version used to store frozen files and to calculate the base package name If no version is supplied the frozenDir is inspected for existing versions and tries to increment. If no prior version is found starts with version 1 1
frozenDir Output directory for the frozen persistence files ${project.basedir}/src/migration/ ${project.basedir}/migration/
persistenceClassesFileList Define persistence classes to freeze (can be used in conjunction with persistenceClassesGlobList) Requires one of persistenceClassesFileList, persistenceClassesGlobList <persistenceClassesFileList>
  <file>src/main/java/my/db/classes/Person.java</file>
  <file>src/main/java/my/db/classes/pkg</file>
  ...
</persistenceClassesFileList>
persistenceClassesGlobList Define persistence classes to freeze (can be used in conjunction with persistenceClassesFileList) Requires one of persistenceClassesFileList, persistenceClassesGlobList <persistenceClassesGlobList>
  <glob>path/relative/to/./src/main/java/my/db/classes/C*.java</glob>
  ...
  <glob>
    <basePath>${project.build.sourceDirectory}</basePath>
    <pattern>Bi*.java</pattern>
  </glob>
</persistenceClassesGlobList>
persistenceResourcesFileList Define resources to freeze (can be used in conjunction with persistenceResourcesGlobList) Requires one of persistenceResourcesFileList, persistenceResourcesGlobList <persistenceResourcesFileList>
  <file>src/main/resources/logging.xml</file>
  <file>src/main/resources/config</file>
  ...
</persistenceResourcesFileList>
persistenceResourcesGlobList Define resources to freeze (can be used in conjunction with persistenceResourcesFileList) Requires one of persistenceResourcesFileList, persistenceResourcesGlobList <persistenceResourcesGlobList>
  <glob>path/relative/to/./src/main/resources/*.xml_bak</glob>
  ...
  <glob>
    <basePath>${project.build.resourceDirectory}</basePath>
    <pattern>*.conf</pattern>
  </glob>
</persistenceResourcesGlobList>
resourceFilteringExcludeFileList List of persistenceResourcesFiles that should not be considered when replacing package references (can be used in conjunction with resourceFilteringExcludeGlobList) Defaults to empty list <resourceFilteringExcludeFileList>
  <file>src/main/resources/logging.xml</file>
  <file>src/main/resources/config</file>
  ...
</resourceFilteringExcludeFileList>
resourceFilteringExcludeGlobList List of persistenceResourcesGlobs that should not be considered when replacing package references (can be used in conjunction with resourceFilteringExcludeGlobList) Defaults to empty list <resourceFilteringExcludeGlobList>
<glob>path/relative/to/./src/main/resources/*.xml_bak</glob>
  ...
  <glob>
    <basePath>${project.build.resourceDirectory}</basePath>
    <pattern>*.conf</pattern>
  </glob>
</resourceFilteringExcludeGlobList>

Thaw (defaultPhase=Initialize)

Target a range of versioned frozen files to include them for compilation.

Configuration option Description Default/Required Example
frozenDir Directory of the frozen persistence files ${project.basedir}/src/migration/ ${project.basedir}/migration/
versionRange Frozen versions to include as project source. Uses the default maven version range format. Defaults to all versions [15,)

Run git config --add include.path ../.gitconfig to include the template config in your project config.

About

A maven plugin and dependency to create complex migrations on persistent data using Hibernate and Flyway

Resources

License

Stars

Watchers

Forks

Languages