Spring Boot + JPA: 忽略列名注释

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

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

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

不过,我的问题是,为什么没有 name _ policy 设置为 EJB3NamingStrategy的 JPA 会忽略列注释呢?也许冬眠方言与此有关?我正在连接到 MS SQL 2014 Express,我的日志包含:

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

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

ImprovedNamingStrategy将把 CamelCase转换为 SNAKE_CASE,而 EJB3NamingStrategy只是使用表名而没有改变。

如果你不想改变命名策略,你可以用小写字母指定你的列名:

@Column(name="testname")

看起来

@ Column (name = “ . .”)

完全被忽略,除非有

Name _ Strategy = org.hibernate.cfg.EJB3NamingStrategy

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

我花了几个小时想弄明白为什么@Column (name = “ . .”)被忽略了。

对于 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

对我来说唯一有效的解决方案就是上面 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)

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

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

这是因为数据库不关心列的名称是 TestName 还是 TestName (列名不区分大小写! !)。

但是要注意的是,数据库名称和表名称并不适用于这些名称,这些名称在 Unix 系统上是大小写敏感的,但在 Windows 系统上是大小写敏感的(事实上,可能很多人晚上睡不着觉,在 Windows 上工作,但是部署在 linux 上:)

如果您想使用@Column (...) ,那么总是使用小写字母,即使实际的 DB 列是驼峰大小写。

示例: 如果实际的 DB 列名是 TestName,那么使用:

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

如果您不喜欢这样,那么只需将实际的 DB 列名改为: Test _ name

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

Spring 在这种情况下也忽略了注释,但是没有抱怨。解决方案是将它移动到字段,而不是使用 getter。

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

虽然我不能使用官方的答案,但这个问题能够帮助我解决我的问题,让我知道要调查什么。

改变:

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

致:

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

我尝试了以上所有的方法,但都没有效果。这个方法对我很有效:

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

注释 getter 而不是变量

在使用 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;

我也尝试了以上所有的方法,但都没有效果。我在数据库中得到了一个叫做“ 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

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

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

(我是新手,这可能是一个确保逻辑正确性的特性:)