【问题标题】:Spring Boot + JPA : Column name annotation ignoredSpring Boot + JPA:列名注释被忽略
【发布时间】:2014-10-06 15:18:38
【问题描述】:

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

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

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

不过,我的问题是为什么没有将naming_strategy 设置为EJB3NamingStrategy JPA 会忽略列注释?也许hibernate方言与它有关?我正在连接到 MS SQL 2014 Express,并且我的日志包含:

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

【问题讨论】:

  • 这个问题是关于明确提供的列名被更改而不是忽略。它归结为this 被执行而不是预期的transparent variant。 Hibernate 实际上可能会忽略 @Column(name="...") 注释,例如当您使用非预期访问类型时,但这里不是这种情况。

标签: java hibernate jpa spring-boot


【解决方案1】:

对于 Hibernate 5,我通过在 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

【讨论】:

  • spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl ,只需要这个属性来保持名称不变。
  • 我遇到了同样的问题,添加这两个属性为我解决了这个问题。我正在运行 Spring Boot 1.4.3
  • 这也是唯一对我有用的解决方案。我正在使用 Spring Boot 1.4.2
  • 我使用的是 Spring Boot 1.5.9.RELEASE,这篇文章适合我
  • 太棒了.. 我想知道为什么它忽略了我的@Column 注释。最后这对我有帮助。对我来说,我觉得这要么是一个错误,要么是缺少功能。
【解决方案2】:

默认情况下,Spring 使用org.springframework.boot.orm.jpa.SpringNamingStrategy 来生成表名。这是org.hibernate.cfg.ImprovedNamingStrategy 的一个非常薄的扩展。该类中的 tableName 方法传递了一个源 String 值,但它不知道它是来自 @Column.name 属性还是从字段名称隐式生成的。

ImprovedNamingStrategy 会将CamelCase 转换为SNAKE_CASE,而EJB3NamingStrategy 只是使用未更改的表名。

如果您不想更改命名策略,您总是可以将列名指定为小写:

@Column(name="testname")

【讨论】:

  • 嗨,菲尔。通过使用spring boot,我添加了spring.jpa.hibernate.naming.strategy:org.hibernate.cfg.EJB3NamingStrategy。但它看起来不适合我。你能帮帮我吗?
  • 响应的重要部分是把名字小写!我建议不要更改策略,而是将名称小写,因为列名不区分大小写!
  • 我在 MS SQL Server 中有混合大小写的列名,例如 ColumnName。 MS SQL Server 不区分大小写,因此这将在运行时工作,但 JPA 工具抱怨找不到 columname。 @teteArg 的回答解决了这个问题,虽然我只需要PhysicalNamingStrategyStandardImpl
【解决方案3】:

好像

@Column(name="..")

完全忽略,除非有

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

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

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

【讨论】:

【解决方案4】:

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

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

这是有效的,因为数据库不关心您是否将列命名为 TestName 或 testname(列名不区分大小写!!)。

但请注意,这同样不适用于数据库名称和表名称,它们在 Unix 系统上区分大小写,但在 Windows 系统上区分大小写(这一事实可能让很多人在夜间保持清醒,在 Windows 上工作,但在linux上部署:))

【讨论】:

  • 1.实际上这不是真的,列名可能区分大小写,具体取决于您使用的数据库的配置... 2. @Column name - 顾名思义应该是提供数据库列名的地方,而不是框架将更改的某些标识符在运行时..
  • 1.谢谢,您能举一个默认情况下列名区分大小写的 db 示例吗? 2. 实际上@Column 为我们提供了由 PhysicalNamingStrategy 解析为物理名称的逻辑名称,至少这似乎是文档所说的:docs.jboss.org/hibernate/orm/5.1/userguide/html_single/chapters/…
  • 1.对不起,我不能,因为我不在乎默认情况下哪个有它,我关心 DBA 在我正在使用的那个上设置了什么设置。 2. 不幸的是,这只是我个人的看法,这种方法是错误的,因为它迫使我思考名称将如何映射到最后的列,或者使用哪种命名策略不涉及提供的名称。
  • 没错,这将是最直观的解决方案,当然更好的文档也不会受到伤害。
  • 显式设置的列名在所有情况下都应覆盖隐式生成的列名。如果没有,那就是 JPA 实现中的一个错误。
【解决方案5】:

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

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)

【讨论】:

    【解决方案6】:

    teteArg,非常感谢。 只是一个补充信息,所以遇到这个问题的每个人都可以理解为什么。

    teteArg 所说的内容在 Spring Boot Common Properties 上注明:http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html

    显然,spring.jpa.hibernate.naming.strategy 不是使用 Hibernate 5 实现 Spring JPA 的受支持属性。

    【讨论】:

      【解决方案7】:

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

      虽然我无法使用官方答案,但该问题能够通过让我知道要调查什么来帮助我解决问题。

      变化:

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

      收件人:

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

      【讨论】:

        【解决方案8】:

        使用 spring jpa 时必须遵循一些命名策略。列名应为小写或大写。

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

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

        请记住,如果您在数据库中有列名“test_name”格式,那么您必须遵循以下方式

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

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

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

        【讨论】:

          【解决方案9】:

          如果您想使用@Column(...),请始终使用小写字母,即使您的实际 DB 列是驼峰式的。

          示例:如果您的实际数据库列名称是 TestName,则使用:

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

          如果您不喜欢这样,只需将实际的 DB 列名称更改为: 测试名称

          【讨论】:

            【解决方案10】:

            在我的例子中,注释在 getter() 方法上,而不是字段本身(从遗留应用程序移植)。

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

            【讨论】:

              【解决方案11】:

              以上方法我都试过了,还是不行。这对我有用:

              @Column(name="TestName")
              public String getTestName(){//.........
              

              注释getter而不是变量

              【讨论】:

                【解决方案12】:

                我也尝试了以上所有方法,但没有任何效果。我在 DB 中有一个名为“gunName”的字段,但我无法处理这个,直到我使用了下面的示例:

                @Column(name="\"gunName\"")
                public String gunName;
                

                带有属性:

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

                还可以看到: https://stackoverflow.com/a/35708531

                【讨论】:

                • 你确定你的db表名中直接有引号吗?
                • 只有那个也对我有用。我认为 JPA 应该提供帮助,而不是给我们带来免费的麻烦。 @Kamil,我的没有引号,这是唯一有效的。也许这是 PostgreSQL 的特殊问题,idk。
                【解决方案13】:

                使用 maven 3.8.3,我发现表的列名遵循 get/set 方法命名的有趣案例。即使我在实体中添加了新字段,如果我没有指定 get/set 方法,它也不会在表中创建新列。

                但是,如果我从实体类中删除所有 get/set 方法,则表中列的命名遵循实体类中字段的命名。

                (我是菜鸟,这可能是一个确保逻辑正确性的功能:)

                【讨论】:

                • 我不认为这是一个 Maven 版本问题
                猜你喜欢
                • 2017-05-04
                • 2012-05-19
                • 1970-01-01
                • 2015-04-14
                • 1970-01-01
                • 2021-01-23
                • 2018-02-25
                • 2018-07-07
                • 2013-11-05
                相关资源
                最近更新 更多