Hibernate not using @Table when doing DDL validation on startup. Using Flyway and TestContainers

Viewed 811

I am having an issue with Hibernate. I am creating tables via Flyway migrations. A snippet is shown below of part of the initial migration script. The script does run (I can see it in DEBUG mode).

Following the script running, Hibernate's validator seems to not be using the table name for the entity I have provided it via javax.persistence.

Here is the entity with some omissions for clarity:


import javax.persistence.*;


@Entity
@Table(name = "IngredientCategories")
public class IngredientCategory implements IEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @Column(nullable = false, length = 128)
    private String name;

    ...
}
CREATE TABLE `IngredientCategories` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `description` varchar(255) DEFAULT NULL,
  `name` varchar(128) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

Looking at the logs, the Flyway migrations are run and then afterwards I get the hibernate validation errors.

2020-10-24 11:22:11.952 DEBUG 91583 --- [           main] o.f.core.internal.command.DbMigrate      : Successfully completed migration of schema `test` to version 1 - init
2020-10-24 11:22:11.961 DEBUG 91583 --- [           main] o.f.c.i.s.JdbcTableSchemaHistory         : Schema History table `test`.`flyway_schema_history` successfully updated to reflect changes
2020-10-24 11:22:11.970  INFO 91583 --- [           main] o.f.core.internal.command.DbMigrate      : Successfully applied 1 migration to schema `test` (execution time 00:00.107s)
2020-10-24 11:22:11.972 DEBUG 91583 --- [           main] org.flywaydb.core.Flyway                 : Memory usage: 82 of 354M
2020-10-24 11:22:12.088  INFO 91583 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [name: default]
2020-10-24 11:22:12.125  INFO 91583 --- [           main] org.hibernate.Version                    : HHH000412: Hibernate ORM core version 5.4.20.Final
2020-10-24 11:22:12.237  INFO 91583 --- [           main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.1.0.Final}
2020-10-24 11:22:12.350  INFO 91583 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.MySQL8Dialect
2020-10-24 11:22:12.998  WARN 91583 --- [           main] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.tool.schema.spi.SchemaManagementException: Schema-validation: missing table [ingredient_categories]
2020-10-24 11:22:12.998  INFO 91583 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2020-10-24 11:22:13.420  INFO 91583 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.
2020-10-24 11:22:13.428  INFO 91583 --- [           main] ConditionEvaluationReportLoggingListener : 

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-10-24 11:22:13.434 ERROR 91583 --- [           main] o.s.boot.SpringApplication               : Application run failed

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.tool.schema.spi.SchemaManagementException: Schema-validation: missing table [ingredient_categories]

I can not decide if this is a hibernate issue, a Flyway issue or a testing issue.

It is just a test "booting" the app:

@SpringBootTest
@Testcontainers
class DataApplicationTests {

    @Test
    void contextLoads() {
    }

}

I have had a look around and can see that many people had an issue before Spring 2x where the tables were validated BEFORE flyway would generate schema...but it seems that that has been "fixed" and the default is Flyway migrations are run before.

The line where I think the issue shows Hibernate was expecting a table name of Schema-validation: missing table [ingredient_categories] So it seems to be not using the javax.constaint.Table @Table(name="IngredientCategories") annotation when running the and building the context/beans.

The app properties are not overly exciting...I am using TestContainers:

#=========INTEGRATION TESTS========#

## Using TestContainers
spring.datasource.url=jdbc:tc:mysql:8.0.22:///

# Validate Schema
spring.jpa.hibernate.ddl-auto = validate

logging.level.org.flywaydb=DEBUG
1 Answers

From official doc

By default, Spring Boot configures the physical naming strategy with SpringPhysicalNamingStrategy. This implementation provides the same table structure as Hibernate 4: all dots are replaced by underscores and camel casing is replaced by underscores as well. By default, all table names are generated in lower case, but it is possible to override that flag if your schema requires it.

For example, a TelephoneNumber entity is mapped to the telephone_number table.

So IngredientCategories became ingredient_categories. For database table name general convention to use snake-case. You can create table with name in snake case

CREATE TABLE `ingredient_categories`

Or if you prefer to use Hibernate 5’s default instead , set the following property:

spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

Then your table's name remains IngredientCategories as given in @Table annotation. Details about Hibernate 5 Naming Strategy Configuration

Related