我有一个具有依赖项 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
@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
默认情况下,Spring 使用 org.springframework.boot.orm.jpa.SpringNamingStrategy
生成表名。这是 org.hibernate.cfg.ImprovedNamingStrategy
的一个非常细的扩展。该类中的 tableName
方法传递了一个源 String
值,但它不知道它是来自 @Column.name
属性还是从字段名称隐式生成的。
ImprovedNamingStrategy
会将 CamelCase
转换为 SNAKE_CASE
,其中 EJB3NamingStrategy
只使用未更改的表名。
如果您不想更改命名策略,您总是可以只用小写指定列名:
@Column(name="testname")
ColumnName
。 MS SQL Server 不区分大小写,因此这将在运行时工作,但 JPA 工具抱怨找不到 columname
。 @teteArg 的回答解决了这个问题,虽然我只需要 PhysicalNamingStrategyStandardImpl
。
看起来
@Column(name="..")
被完全忽略,除非有
spring.jpa.hibernate.naming_strategy=org.hibernate.cfg.EJB3NamingStrategy
指定,所以对我来说这是一个错误。
我花了几个小时试图弄清楚为什么 @Column(name="..") 被忽略了。
@Column(name="TestName")
的默认策略是 test_name
,这是正确的行为!
如果您的数据库中有一个名为 TestName
的列,则应将 Column annotation 更改为 @Column(name="testname")
。
这是有效的,因为数据库不关心您是否将列命名为 TestName 或 testname(列名不区分大小写!!)。
但请注意,这不适用于数据库名称和表名称,它们在 Unix 系统上区分大小写,但在 Windows 系统上区分大小写(这一事实可能让很多人在晚上保持清醒,在 Windows 上工作,但在 linux 上部署:))
唯一对我有用的解决方案是上面 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)
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 实现的受支持属性。
结果我只需要将 @column
名称 testName 转换为所有小写字母,因为它最初是驼峰式的。
尽管我无法使用官方答案,但该问题能够通过让我知道要调查什么来帮助我解决问题。
改变:
@Column(name="testName")
private String testName;
至:
@Column(name="testname")
private String testName;
使用 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;
如果您想使用@Column(...),请始终使用小写字母,即使您的实际 DB 列是驼峰式的。
示例:如果您的实际数据库列名称是 TestName
,则使用:
@Column(name="testname") //all small-case
如果您不喜欢这样,只需将实际的数据库列名称更改为:test_name
我也尝试了以上所有方法,但没有任何效果。我在数据库中有一个名为“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
在我的例子中,注释在 getter() 方法上,而不是字段本身(从遗留应用程序移植)。
在这种情况下,Spring 也会忽略注释,但不会抱怨。解决方案是将其移动到现场而不是吸气剂。
我尝试了以上所有方法,但没有成功。这对我有用:
@Column(name="TestName")
public String getTestName(){//.........
注释 getter 而不是变量
使用 maven 3.8.3,我发现表的列名遵循 get/set 方法命名的有趣案例。即使我在实体中添加了一个新字段,如果我没有指定 get/set 方法,它也不会在表中创建一个新列。
但是,如果我从实体类中删除所有 get/set 方法,则表中列的命名遵循实体类中字段的命名。
(我是菜鸟,它可能是一个确保逻辑正确性的功能:)
不定期副业成功案例分享