为什么Spring Data / Hibernate在表名为"productDef"的情况下查询"product_def"表?
为什么Spring Data / Hibernate在表名为"productDef"的情况下查询"product_def"表?
我正在使用Spring Boot 2.3.4 / Spring Data / Hibernate / MySQL 8。
我的数据库表名为"productDef"。我有一个实体对象"ProductDef"。
当我执行"list all"查询时,我收到以下错误消息...
java.sql.SQLSyntaxErrorException: 表'mydatabase.product_def'不存在
为什么Hibernate在寻找"product_def"表?
我尝试给实体添加注解@Table(name="productDef")
,但没有起作用。
如果我将数据库表重命名为"product_def",我的代码就可以工作。但不幸的是,我不能为我的项目重命名数据库表。
我错过了什么?
更新:
解决方案是实现一个自定义的PhysicalNamingStrategy,防止"productDef"变成"product_def"。
然而,尽管这对@Table名称注解起作用,但对@Column名称注解没有起作用。
根据这个讨论线程,忽略@Column名称注解是一个bug。
在application.properties中添加以下内容:
spring.jpa.properties.hibernate.physical_naming_strategy=com.myapp.dao.RealNamingStrategyImpl
并实现以下类:
package com.myapp.dao; import java.io.Serializable; import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.naming.PhysicalNamingStrategy; import org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; public class RealNamingStrategyImpl extends org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy implements Serializable { public static final PhysicalNamingStrategy INSTANCE = new PhysicalNamingStrategyStandardImpl(); @Override public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) { return new Identifier(name.getText(), name.isQuoted()); } @Override public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment context) { return new Identifier(name.getText(), name.isQuoted()); } }
问题出现的原因是Hibernate默认使用的命名策略将驼峰命名转换为下划线命名,所以在查询"productDef"表时会转为查询"product_def"表。解决方法是配置自定义的命名策略,可以通过配置文件或者注解来实现。
在Hibernate中,默认的命名策略是由JPA 2.0定义的,即physicalNamingStrategy。它将驼峰命名转换为下划线命名。可以通过配置"hibernate.physical_naming_strategy"来指定使用的命名策略。
在Spring中,可以通过配置属性"spring.jpa.hibernate.naming.physical-strategy"来配置命名策略。
默认情况下,Spring Boot使用的是SpringPhysicalNamingStrategy作为物理命名策略。它与Hibernate 4的表结构相同,将所有的点替换为下划线,并将驼峰命名也替换为下划线。默认情况下,所有表名都是小写的,但如果需要,可以覆盖该标志。
然而,如果希望强制Hibernate使用表名"productDef",需要实现自定义的命名策略。这是因为Hibernate有两种策略类型,分别是"implicit"和"physical"。注解可以绕过"implicit"策略,但无论是否有注解,所有的操作都会经过"physical"策略。因此,需要重写"physical"策略来达到目的。
在实现了自定义的SpringPhysicalNamingStrategy后,表名的问题得到了解决。然而,对于列名仍然存在同样的问题。经过一番调查发现,这是一个已知的bug,注解被忽略了。可以在该讨论线程中找到更多信息。
提问者在另外的问题中提到了关于"ignored"注解的问题,并发表了相关讨论。