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

Posted

技术标签:

【中文标题】Hibernate 在启动时进行 DDL 验证时不使用 @Table。使用 Flyway 和 TestContainers【英文标题】:Hibernate not using @Table when doing DDL validation on startup. Using Flyway and TestContainers 【发布时间】:2021-02-07 06:08:01 【问题描述】:

我遇到了休眠问题。 我正在通过 Flyway 迁移创建表。 下面显示了初始迁移脚本的一部分的 sn-p。 该脚本确实运行(我可以在 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 迁移运行,然后之后我得到了休眠验证错误。

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]

我无法确定这是休眠问题、Flyway 问题还是测试问题。

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

@SpringBootTest
@Testcontainers
class DataApplicationTests 

    @Test
    void contextLoads() 
    


我环顾四周,可以看到很多人在 Spring 2x 之前遇到了问题,其中在 flyway 生成模式之前验证了表......但似乎已经“修复”并且默认是 Flyway 迁移之前运行过。

我认为问题显示 Hibernate 期望表名的行 Schema-validation: missing table [ingredient_categories] 因此,在运行和构建上下文/bean 时,它似乎没有使用 javax.constaint.Table @Table(name="IngredientCategories") 注释。

应用属性并不过分令人兴奋...我正在使用 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】:

来自官方doc

默认情况下,Spring Boot 配置物理命名策略为 SpringPhysicalNamingStrategy。这个实现提供了相同的 表结构为 Hibernate 4:所有点都替换为下划线 camel 大小写也被下划线替换。默认情况下,所有 表名以小写形式生成,但可以 如果您的架构需要,请覆盖该标志。

例如,TelephoneNumber 实体映射到 电话号码表

所以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 Naming Strategy Configuration的详细信息

【讨论】:

谢谢。我可能会切换回做snake_case。我过去一直只是使用休眠,让它设置表和列的名称。我会遵守约定,但很高兴知道您可以更改它:)。 进一步补充,这可能听起来很愚蠢,但如果你使用 @Table(name="MyTableName") 是唯一真正的目的是链接一个实体,如果它有非常不同的表名说添加休眠到一个非常遗留的系统?就像实际的旧表名称是“factory_personel”一样,但在代码中已选择让表由“FactoryWorker”表示? 其实,一切都取决于选择,你也可以实施你的命名策略。详细解释见这里docs.jboss.org/hibernate/orm/5.1/userguide/html_single/chapters/… 并且大小写转换是一项额外的功能,因为 CamelCase 是 Java 中的通用约定和数据库的蛇形大小写。

以上是关于Hibernate 在启动时进行 DDL 验证时不使用 @Table。使用 Flyway 和 TestContainers的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Hibernate Envers 在更新时不启动?

休眠 - hibernate.hbm2ddl.auto = 验证

我可以在 Play 上记录 hibernate 的 DDL 代码吗?启动?

用于在链接服务器上执行 DDL 语句的 Powershell 脚本 - 使用 SSIS 运行时不起作用

spring.jpa.hibernate.ddl-auto 属性在 Spring 中是如何工作的?

在休眠多租户应用程序中启动时不查找数据源