Hibernate在启动时执行DDL验证时未使用@Table。 使用Flyway和TestContainers。

huangapple go评论93阅读模式
英文:

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

问题

我遇到了 Hibernate 的问题。
我正在通过 Flyway 迁移创建表。
下面显示了初始迁移脚本的一部分片段。
脚本确实在运行(我可以在 DEBUG 模式下看到)。

在脚本运行后,Hibernate 的验证器似乎没有使用我通过 javax.persistence 提供给它的实体的表名。

以下是为了清晰起见省略了一些内容的实体示例:

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;

查看日志后,Flyway 迁移会在运行,然后在之后我会收到 Hibernate 验证错误。

日志内容如下:

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
...(其他日志)
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]

我不能确定这是一个 Hibernate 的问题、Flyway 的问题还是一个测试问题。

这只是一个“启动”应用程序的测试:

@SpringBootTest
@Testcontainers
class DataApplicationTests {

	@Test
	void contextLoads() {
	}

}

我查看了一下,许多人在 Spring 2x 之前就遇到了一个问题,即在 Flyway 生成模式之前会验证表... 但是似乎这个问题已经被“修复”,默认情况下是在运行 Flyway 迁移之前运行的。

我认为问题出现在这一行,Hibernate 期望表名为:
Schema-validation: missing table [ingredient_categories]
所以似乎在运行和构建上下文/bean 时没有使用 @Table(name="IngredientCategories") 注解。

应用程序属性并不是特别令人兴奋... 我正在使用 TestContainers:

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

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

# 验证模式
spring.jpa.hibernate.ddl-auto = validate

logging.level.org.flywaydb=DEBUG
英文:

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

得分: 1

从官方文档

默认情况下,Spring Boot 使用 SpringPhysicalNamingStrategy 配置物理命名策略。该实现提供了与 Hibernate 4 相同的表结构:所有点号都被下划线替代,驼峰命名法也被替换为下划线。默认情况下,所有表名都以小写生成,但如果您的模式需要,可以覆盖该标志。

例如,一个 TelephoneNumber 实体被映射到 telephone_number 表

因此,IngredientCategories 变为 ingredient_categories。对于数据库表名的一般约定是使用蛇形命名法。您可以使用蛇形命名法创建表名:

CREATE TABLE `ingredient_categories`

或者,如果您更喜欢使用 Hibernate 5 的默认值,则设置以下属性:

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

然后您表的名称将保持为 IngredientCategories,如 @Table 注解中所给出的。有关 Hibernate 5 命名策略配置 的详细信息。

英文:

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

huangapple
  • 本文由 发表于 2020年10月24日 18:43:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/64512485.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定