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.hbm2ddl.auto = 验证
我可以在 Play 上记录 hibernate 的 DDL 代码吗?启动?
用于在链接服务器上执行 DDL 语句的 Powershell 脚本 - 使用 SSIS 运行时不起作用