Spring Boot + JPA:列名注释被忽略


121

我有一个带有依赖项的Spring Boot应用程序spring-boot-starter-data-jpa。我的实体类具有带有列名称的列注释。例如:

@Column(name="TestName")
private String testName;

由此生成的SQL创建test_name为列名。在寻找解决方案之后,我发现spring.jpa.hibernate.naming_strategy=org.hibernate.cfg.EJB3NamingStrategy解决了该问题(列名来自列注释)。

我的问题仍然是,为什么不将naming_strategy设置为EJB3NamingStrategyJPA就会忽略列注释?也许休眠方言与此有关?我正在连接到MS SQL 2014 Express,我的日志包含:

Unknown Microsoft SQL Server major version [12] using SQL Server 2000 dialect
Using dialect: org.hibernate.dialect.SQLServerDialect 

1
这个问题是关于显式提供的列名被更改而不是被忽略。归结为正在执行,而不是预期的透明变体。Hibernate实际上可能会忽略@Column(name="...")注释,例如,当您使用非预期的访问类型时,但这不是这种情况。
VlastimilOvčáčík16年

Answers:


163

对于hibernate5,我通过将下一行放在application.properties文件中解决了此问题:

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

30
spring.jpa.hibernate.naming.physical-strategy = org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl,只需要此属性即可保持名称不变。
abhishek ringia '16

1
我有同样的问题,添加这两个属性为我解决了。我正在运行Spring Boot 1.4.3
Johan

1
这也是唯一对我有用的解决方案。我正在使用Spring Boot 1.4.2
Sanjiv Jivan,2017年

我正在使用Spring Boot 1.5.9.RELEASE,此帖子对我
有用

太棒了..我想知道为什么它忽略了我的@Column注释。最终,这对我有所帮助。对我来说,我觉得这是一个错误或功能缺失。
Raju Penumatsa

86

默认情况下,Spring用于org.springframework.boot.orm.jpa.SpringNamingStrategy生成表名。这是的很细的扩展org.hibernate.cfg.ImprovedNamingStrategytableName该类中的方法将传递一个源String值,但是它不知道它是否来自@Column.name属性或是否已从字段名称隐式生成。

ImprovedNamingStrategy会转换CamelCaseSNAKE_CASE其中的EJB3NamingStrategy只是使用表名不变。

如果您不想更改命名策略,则可以始终以小写形式指定列名称:

@Column(name="testname")

1
嗨,菲尔 通过使用Spring Boot,我添加了spring.jpa.hibernate.naming.strategy:org.hibernate.cfg.EJB3NamingStrategy。但这似乎对我不起作用。你能帮助我吗?
BeeNoisy

响应的重要部分是将名称小写!我建议不要更改策略,而应使用小写字母,因为列名不区分大小写!
loicmathieu

31

看起来

@Column(name =“ ..”)

除非有

spring.jpa.hibernate.naming_strategy = org.hibernate.cfg.EJB3NamingStrategy

指定,所以对我来说这是一个错误。

我花了几个小时试图弄清楚为什么@Column(name =“ ..”)被忽略了。


4
我有同样的问题。我在这里添加了一个问题报告:github.com/spring-projects/spring-boot/issues/2129
Kacper86

非常感谢。将我的应用程序指向现有数据库丢失了大约一天。
德米特里·埃罗欣

实际上,它不会被忽略,只是默认的spring命名策略应用于给定的name属性。阅读@PhilWebb答案
Michel Feldheim,

15

的默认策略@Column(name="TestName")test_name,这是正确的行为!

如果您TestName的数据库中有一个命名列,则应将Column注解更改为@Column(name="testname")

这行得通,因为数据库不在乎您是将列名命名为 TestName还是testname(列名不区分大小写!!)。

但是请注意,这不适用于数据库名称和表名称,它们在Unix系统上区分大小写,但在Windows系统上区分大小写(这一事实可能使很多人在晚上醒着,在Windows上工作但在linux上进行部署:))


3
1.事实并非如此,列名称可能区分大小写,具体取决于您所使用的数据库的配置... 2. @列名称-顾名思义,该名称应该是提供数据库列名称的位置,而不是框架提供的某些标识符将在运行时更改
。.– Kamil

1.谢谢,您能举一个默认情况下列名区分大小写的db示例吗?2.实际上,@ Column为我们提供了逻辑名称,这些逻辑名称由PhysicalNamingStrategy解析为物理名称,至少这似乎是文档所说的:docs.jboss.org/hibernate/orm/5.1/userguide/html_single/chapters / ...
奥尔罕

2
1.对不起,我不能,因为我不在乎默认情况下有哪个设置,我在乎DBA在我正在使用的设置上设置了哪些设置。2.不幸的是,这是我的个人观点,因为这种方法是错误的,因为它迫使我思考或思考名称将如何最终映射到列,或者使用哪种命名策略不会影响提供的名称。
卡米尔2015年

1
没错,那将是最直观的解决方案,当然,对此有更好的文档也不会受到损害。
奥罕

在所有情况下,显式设置的列名都应覆盖隐式生成的列名。如果不是,那是JPA实现中的一个错误。
jwenting

13

唯一对我有用的解决方案是上面teteArg发布的解决方案。我使用的是Spring Boot 1.4.2 w / Hibernate5。即

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

为了获得更多见解,我将发布呼叫跟踪,以便其清晰地了解Spring正在调用Hibernate来设置命名策略。

      at org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl.toPhysicalColumnName(PhysicalNamingStrategyStandardImpl.java:46)
  at org.hibernate.cfg.Ejb3Column.redefineColumnName(Ejb3Column.java:309)
  at org.hibernate.cfg.Ejb3Column.initMappingColumn(Ejb3Column.java:234)
  at org.hibernate.cfg.Ejb3Column.bind(Ejb3Column.java:206)
  at org.hibernate.cfg.Ejb3DiscriminatorColumn.buildDiscriminatorColumn(Ejb3DiscriminatorColumn.java:82)
  at org.hibernate.cfg.AnnotationBinder.processSingleTableDiscriminatorProperties(AnnotationBinder.java:797)
  at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:561)
  at org.hibernate.boot.model.source.internal.annotations.AnnotationMetadataSourceProcessorImpl.processEntityHierarchies(AnnotationMetadataSourceProcessorImpl.java:245)
  at org.hibernate.boot.model.process.spi.MetadataBuildingProcess$1.processEntityHierarchies(MetadataBuildingProcess.java:222)
  at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:265)
  at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:847)
  at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:874)
  at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:60)
  at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:353)
  at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:373)
  at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:362)
  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1642)
  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1579)
  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)
  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
  at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
  at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
  - locked <0x1687> (a java.util.concurrent.ConcurrentHashMap)
  at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
  at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
  at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1081)
  at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:856)
  at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:542)
  - locked <0x1688> (a java.lang.Object)
  at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:761)
  at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:371)
  at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
  at org.springframework.boot.SpringApplication.run(SpringApplication.java:1186)
  at org.springframework.boot.SpringApplication.run(SpringApplication.java:1175)


4

原来我只需要转换 @column名称testName为所有小写字母,因为它最初是驼峰式的。

尽管我无法使用官方答案,但该问题仍然可以通过让我知道要调查的内容来帮助我解决问题。

更改:

@Column(name="testName")
private String testName;

至:

@Column(name="testname")
private String testName;

3

如果要使用@Column(...),则即使实际的数据库列为驼峰式格式,也始终使用小写字母。

示例:如果您的实际数据库列名称为TestName

  @Column(name="testname") //all small-case

如果您不喜欢,则只需将实际的数据库列名称更改为:test_name


1

在我的情况下,注释位于getter()方法上,而不是字段本身(从旧版应用程序移植)。

在这种情况下,Spring也会忽略注释,但不会抱怨。解决方案是将其移至字段而不是吸气剂。


1
感谢更新。确实有价值的信息。
jwenting
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.