java Spring data + hibernate 使用了错误的列名

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28299415/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 13:21:53  来源:igfitidea点击:

Spring data + hibernate uses wrong column name

javaspringhibernatespring-boot

提问by Colin Breame

Using Spring Data + hibernate, Hibernate is configured to automatically create the schema. However when querying an exception is thrown (see below).

使用 Spring Data + hibernate,将 Hibernate 配置为自动创建模式。但是查询时会抛出异常(见下文)。

It looks like the column name used during automatic schema creation is different than the column name for the query.

看起来自动模式创建期间使用的列名与查询的列名不同。

If I configure LocalSessionFactoryBeanto use a naming strategy the problem disappears and the test works.

如果我配置LocalSessionFactoryBean为使用命名策略,问题就会消失并且测试有效。

Is this a bug? or am I misunderstanding something?

这是一个错误吗?还是我误解了什么?

The setup is below.

设置如下。

[Edit] As per the log below the message ERROR: column datum0_.datum_id does not existis present. However the column is actually named datumId, as can be seen from the logged SQL:

[编辑] 根据下面的日志,该消息ERROR: column datum0_.datum_id does not exist存在。然而,该列实际上是命名的datumId,从记录的 SQL 中可以看出:

create table Datum (
    datumId int4 not null,
    value varchar(255),
    primary key (datumId)
)


Application.java:

应用程序.java:

package test;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;

@Configuration
@ImportResource("classpath:Application.xml")
@EnableAutoConfiguration
public class Application {
    static Log log = LogFactory.getLog(Application.class);

    public static void main(String[] args) throws Exception {
        ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
        DatumRepository repository = context.getBean(DatumRepository.class);
        repository.findAll();
    }
}

Datum.java:

数据.java:

package test;

import javax.persistence.*;

@Entity
public class Datum {
    @Id
    @GeneratedValue
    private int datumId;

    @Column
    private String value;

    public int getDatumId() {
        return datumId;
    }

    public void setDatumId(int datumId) {
        this.datumId = datumId;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}

DatumRepository.java:

DatumRepository.java:

package test;

import org.springframework.data.repository.CrudRepository;

public interface DatumRepository extends CrudRepository<Datum, Integer> {
}

Application.xml:

应用程序.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:jpa="http://www.springframework.org/schema/data/jpa"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                            http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

    <!--Searches for @Configuration classes and stereotypes-->
    <context:component-scan base-package="test" />

    <!--Searches for @Autowired/@Inject-->
    <context:annotation-config />

    <!-- For creation of repositories -->
    <!--<jpa:repositories base-package="test" />-->

    <!--Data source-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="org.postgresql.Driver"/>
        <property name="url" value="jdbc:postgresql://localhost/nexus"/>
        <property name="username" value="nexus"/>
        <property name="password" value="nexus"/>
    </bean>

    <!-- Hibernate -->
    <bean class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="packagesToScan" value="test" />
        <!--<property name="namingStrategy"><ref bean="naming" /></property>-->

        <property name="hibernateProperties">
            <value>
                hibernate.hbm2ddl.auto=create-drop
                hibernate.show_sql=true
                hibernate.format_sql=true
            </value>
        </property>
    </bean>

    <bean id="naming" class="org.hibernate.cfg.ImprovedNamingStrategy"></bean>
</beans>

pom.xml:

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>test</groupId>
    <artifactId>test1</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.2.1.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>9.3-1100-jdbc41</version>
        </dependency>

        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>1.4</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-releases</id>
            <url>https://repo.spring.io/libs-release</url>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>spring-releases</id>
            <url>https://repo.spring.io/libs-release</url>
        </pluginRepository>
    </pluginRepositories>

</project>

(edit) output + exception:

(编辑)输出+异常:

2015-02-03 13:49:14.697  INFO 3515 --- [lication.main()] test.Application                         : Starting Application on desktop with PID 3515 (/home/breamec/src/test1/target/classes started by breamec in /home/breamec/src/test1)
2015-02-03 13:49:14.747  INFO 3515 --- [lication.main()] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@5b525b5f: startup date [Tue Feb 03 13:49:14 GMT 2015]; root of context hierarchy
2015-02-03 13:49:15.232  INFO 3515 --- [lication.main()] o.s.b.f.xml.XmlBeanDefinitionReader      : Loading XML bean definitions from class path resource [Application.xml]
2015-02-03 13:49:16.070  INFO 3515 --- [lication.main()] o.s.j.d.DriverManagerDataSource          : Loaded JDBC driver: org.postgresql.Driver
2015-02-03 13:49:16.308  INFO 3515 --- [lication.main()] j.LocalContainerEntityManagerFactoryBean : Building JPA container EntityManagerFactory for persistence unit 'default'
2015-02-03 13:49:16.340  INFO 3515 --- [lication.main()] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [
    name: default
    ...]
2015-02-03 13:49:16.454  INFO 3515 --- [lication.main()] org.hibernate.Version                    : HHH000412: Hibernate Core {4.3.7.Final}
2015-02-03 13:49:16.457  INFO 3515 --- [lication.main()] org.hibernate.cfg.Environment            : HHH000206: hibernate.properties not found
2015-02-03 13:49:16.458  INFO 3515 --- [lication.main()] org.hibernate.cfg.Environment            : HHH000021: Bytecode provider name : javassist
2015-02-03 13:49:16.683  INFO 3515 --- [lication.main()] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {4.0.5.Final}
2015-02-03 13:49:17.202  INFO 3515 --- [lication.main()] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.PostgreSQL9Dialect
2015-02-03 13:49:17.218  INFO 3515 --- [lication.main()] o.h.e.jdbc.internal.LobCreatorBuilder    : HHH000424: Disabling contextual LOB creation as createClob() method threw error : java.lang.reflect.InvocationTargetException
2015-02-03 13:49:17.355  INFO 3515 --- [lication.main()] o.h.h.i.ast.ASTQueryTranslatorFactory    : HHH000397: Using ASTQueryTranslatorFactory
2015-02-03 13:49:18.189  INFO 3515 --- [lication.main()] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.PostgreSQL9Dialect
2015-02-03 13:49:18.190  INFO 3515 --- [lication.main()] o.h.e.jdbc.internal.LobCreatorBuilder    : HHH000424: Disabling contextual LOB creation as createClob() method threw error : java.lang.reflect.InvocationTargetException
2015-02-03 13:49:18.199  INFO 3515 --- [lication.main()] o.h.e.t.i.TransactionFactoryInitiator    : HHH000399: Using default transaction strategy (direct JDBC transactions)
2015-02-03 13:49:18.199  INFO 3515 --- [lication.main()] o.h.h.i.ast.ASTQueryTranslatorFactory    : HHH000397: Using ASTQueryTranslatorFactory
2015-02-03 13:49:18.211  INFO 3515 --- [lication.main()] org.hibernate.tool.hbm2ddl.SchemaExport  : HHH000227: Running hbm2ddl schema export
Hibernate: 
    drop table Datum cascade
2015-02-03 13:49:18.219 ERROR 3515 --- [lication.main()] org.hibernate.tool.hbm2ddl.SchemaExport  : HHH000389: Unsuccessful: drop table Datum cascade
2015-02-03 13:49:18.219 ERROR 3515 --- [lication.main()] org.hibernate.tool.hbm2ddl.SchemaExport  : ERROR: table "datum" does not exist
Hibernate: 
    drop sequence hibernate_sequence
2015-02-03 13:49:18.221 ERROR 3515 --- [lication.main()] org.hibernate.tool.hbm2ddl.SchemaExport  : HHH000389: Unsuccessful: drop sequence hibernate_sequence
2015-02-03 13:49:18.221 ERROR 3515 --- [lication.main()] org.hibernate.tool.hbm2ddl.SchemaExport  : ERROR: sequence "hibernate_sequence" does not exist
Hibernate: 
    create table Datum (
        datumId int4 not null,
        value varchar(255),
        primary key (datumId)
    )
Hibernate: 
    create sequence hibernate_sequence
2015-02-03 13:49:18.230  INFO 3515 --- [lication.main()] org.hibernate.tool.hbm2ddl.SchemaExport  : HHH000230: Schema export complete
2015-02-03 13:49:18.737  INFO 3515 --- [lication.main()] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2015-02-03 13:49:18.745  INFO 3515 --- [lication.main()] test.Application                         : Started Application in 4.32 seconds (JVM running for 8.385)
2015-02-03 13:49:18.961  WARN 3515 --- [lication.main()] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 0, SQLState: 42703
2015-02-03 13:49:18.961 ERROR 3515 --- [lication.main()] o.h.engine.jdbc.spi.SqlExceptionHelper   : ERROR: column datum0_.datum_id does not exist
  Position: 8
[WARNING] 
java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.springframework.boot.maven.RunMojo$LaunchRunner.run(RunMojo.java:418)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.dao.InvalidDataAccessResourceUsageException: could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:231)
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:214)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:417)
    at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59)
    at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:147)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodIntercceptor.invoke(CrudMethodMetadataPostProcessor.java:122)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
    at com.sun.proxy.$Proxy51.findAll(Unknown Source)
    at test.Application.main(Application.java:20)
    ... 6 more
Caused by: org.hibernate.exception.SQLGrammarException: could not extract ResultSet
    at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:123)
    at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:49)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:126)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:112)
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:91)
    at org.hibernate.loader.Loader.getResultSet(Loader.java:2066)
    at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1863)
    at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1839)
    at org.hibernate.loader.Loader.doQuery(Loader.java:910)
    at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:355)
    at org.hibernate.loader.Loader.doList(Loader.java:2554)
    at org.hibernate.loader.Loader.doList(Loader.java:2540)
    at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2370)
    at org.hibernate.loader.Loader.list(Loader.java:2365)
    at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:497)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:387)
    at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:236)
    at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1264)
    at org.hibernate.internal.QueryImpl.list(QueryImpl.java:103)
    at org.hibernate.jpa.internal.QueryImpl.list(QueryImpl.java:573)
    at org.hibernate.jpa.internal.QueryImpl.getResultList(QueryImpl.java:449)
    at org.hibernate.jpa.criteria.compile.CriteriaQueryTypeQueryAdapter.getResultList(CriteriaQueryTypeQueryAdapter.java:67)
    at org.springframework.data.jpa.repository.support.SimpleJpaRepository.findAll(SimpleJpaRepository.java:289)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:442)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:427)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:381)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.transaction.interceptor.TransactionInterceptor.proceedWithInvocation(TransactionInterceptor.java:99)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
    ... 14 more
Caused by: org.postgresql.util.PSQLException: ERROR: column datum0_.datum_id does not exist
  Position: 8
    at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2161)
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1890)
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:255)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:560)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:417)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.executeQuery(AbstractJdbc2Statement.java:302)
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:82)
    ... 45 more

回答by Bassem Reda Zohdy

SpringNamingStrategy extends ImprovedNamingStrategy

so apply the below :

所以应用以下:

I found the issue it is in ImprovedNamingStrategy if you want to solve it without details use DefaultNamingStrategy instead ImprovedNamingStrategy as below in properties file

我发现问题出在改进的命名策略中,如果你想在没有细节的情况下解决它,请使用 DefaultNamingStrategy 而不是改进的命名策略,如下所示在属性文件中

spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.DefaultNamingStrategy

Details: There are 2 methods in NamingStrategy interface propertyToColumnName and columnName, first one called if you didn't specify name in @Column and 2nd one called if you specify name in @Column.

详细信息: NamingStrategy 接口中的 propertyToColumnName 和 columnName 有 2 个方法,第一个在@Column 中未指定名称时调用,第二个在@Column 中指定名称时调用。

in ImprovedNamingStrategy both change the name from camel to _ format while in DefaultNamingStrategy it is returning name as it is in 2nd method which is from my point of view the correct behavior.

在改进的命名策略中,都将名称从骆驼更改为 _ 格式,而在 DefaultNamingStrategy 中,它返回的名称与第二种方法中的名称相同,这在我看来是正确的行为。

回答by Predrag Maric

By default, Spring Boot uses org.springframework.boot.orm.jpa.SpringNamingStrategy.

默认情况下,Spring Boot 使用org.springframework.boot.orm.jpa.SpringNamingStrategy

Hibernate NamingStrategy that follows Spring recommended naming conventions.

Hibernate NamingStrategy 遵循 Spring 推荐的命名约定。

This naming strategy just takes the field name and deduces a column name based only on that, substituting camel case with underscore. You didn't post the exception, but based on this Hibernate probably queried for datum_idcolumn.

这种命名策略仅采用字段名称并仅基于该名称推导出列名称,用下划线替换驼峰式大小写。您没有发布异常,但基于此 Hibernate 可能查询了datum_id列。

Related issue raised on Spring boot project

Spring boot 项目提出的相关问题

回答by postalservice14

Figured it out.

弄清楚了。

Use DefaultNamingStrategyand backticks in the @Column annotation.

DefaultNamingStrategy在@Column 注释中使用和反引号。

spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.DefaultNamingStrategy

and

@Column(name = "`datumId`")
private int datumId;

回答by Imtiyaz m

Hibernate provides two different naming strategy whereas Spring Boot configures the physical naming strategy with SpringPhysicalNamingStrategywhere all dots are replaced by underscores and camel casing is replaced by underscores and all table names are generated in lower case. For example, a USERDETAILSentity is mapped to the user_detailstable.

Hibernate 提供了两种不同的命名策略,而 Spring Boot 配置了物理命名策略,SpringPhysicalNamingStrategy其中所有点都被下划线替换,驼峰大小写被下划线替换,所有表名都以小写形式生成。例如,一个USERDETAILS实体被映射到user_details表。

If you want to use your own custom naming strategy as implemented above, you can make following configuration in application.properties:

如果你想使用上面实现的自定义命名策略,你可以在 中进行以下配置application.properties

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