The best way to validate the DDL schema with Spring and Hibernate

Imagine having a tool that can automatically detect JPA and Hibernate performance issues. Wouldn’t that be just awesome?

Well, Hypersistence Optimizer is that tool! And it works with Spring Boot, Spring Framework, Jakarta EE, Java EE, Quarkus, or Play Framework.

So, enjoy spending your time on the things you love rather than fixing performance issues in your production system on a Saturday night!

Introduction

In this article, we are going to see what is the best way to validate the DDL schema and the JPA entity mappings when using Spring and Hibernate.

I decided to write this article after reading this Tweet:

The hbm2ddl validate strategy

As I explained in this article, Hibernate provides a SchemaManagementTool that we can use to manage or validate the underlying database schema.

While generating the DDL scripts with this Hibernate tool can be useful only to determine the DB schema that Hibernate expects for the current JPA entity mappings, it’s best to use an automatic schema management tool, like Flyway, to manage your database schema.

However, the Hibernate SchemaManagementTool also offers a validate strategy that can verify whether the JPA entity mappings are compatible with the underlying database schema.

In Spring, you can activate this strategy via the spring.jpa.hibernate.ddl-auto application property:

spring.jpa.hibernate.ddl-auto=validate

Once you provide this setting, the validation will be done every time you bootstrapped Hibernate.

However, since integration tests are meant to run in isolation, it’s common to create and destroy the Hibernate schema for every test execution, and validating the schema for every test execution is just adding an unnecessary overhead.

We can actually measure this overhead like this:

SchemaValidator schemaValidator = getSchemaValidator(sessionFactory);

final ExecutionOptions executionOptions = SchemaManagementToolCoordinator
    .buildExecutionOptions(
        settings,
        ExceptionHandlerHaltImpl.INSTANCE
    );

long startNanos = System.nanoTime();

schemaValidator.doValidation(
    metadataImplementor,
    executionOptions
);

LOGGER.info(
    "Schema validation took: [{}] ms",
    TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNanos)
);

When running this test on Shopizer, which is a non-trivial Spring Boot project with over 100 JPA entities, this is what I get printed in the log:

SchemaValidationTest : Schema validation took: [138] ms

So, if the validation takes 138 milliseconds on every test execution and we have 1000 tests, then the overall overhead of the spring.jpa.hibernate.ddl-auto=validate setting is going to be 2 minutes and 18 seconds.

Not nice!

Now, you may wonder why you’d even need such a validation if you’re already using Flyway or Liquibase to manage your schema.

Even if you are using an automated schema management tool, if you are using JPA, then you must make sure that the entity mappings are compatible with the underlying database schema. Otherwise, your application is not going to work as expected, as the JPA provider might assume a different database schema than the actual one.

So, the purpose of this validation check is to ensure that the JPA entity mappings are compatible with the underlying database schema.

The best way to validate the DDL schema with Spring and Hibernate

Now that we have seen that it’s not useful to validate the schema every time Hibernate bootstraps, let’s see how we can disable the global validation.

To disable the global schema validation, we just need to set the spring.jpa.hibernate.ddl-auto property to the value of none:

spring.jpa.hibernate.ddl-auto=none

Having disabled the global schema validation, we can now activate the spring.jpa.hibernate.ddl-auto=validate setting only for a single Spring test like this:

@DataJpaTest(
    properties = "spring.jpa.hibernate.ddl-auto=validate"
)
@AutoConfigureTestDatabase(replace = Replace.NONE)
public class SchemaValidationTest {

    @Test
    public void testSchemaValidity() {}
    
}

This way, we can still validate the schema, but we do it only once instead of doing it every time the JPA EntityManagerFactory is bootstrapped.

I'm running an online workshop on the 11th of October about High-Performance SQL.

If you enjoyed this article, I bet you are going to love my Book and Video Courses as well.

Conclusion

Validating the DDL schema with the JPA mappings is a very important task, but you should not do that every time Spring runs an integration test because the validation overhead will just add up to the overall time it takes to run your test suite.

By validating the database schema only once, you get exactly the outcome you wanted from the very beginning, but without paying the extra overhead every time you bootstrap JPA and Hibernate.

Transactions and Concurrency Control eBook

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.