Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring data + hibernate uses wrong column name

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

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

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

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 exist is present. However the column is actually named datumId, as can be seen from the logged SQL:

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

Application.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:

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:

package test;

import org.springframework.data.repository.CrudRepository;

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

Application.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:

<?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$1.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
like image 673
Colin Breame Avatar asked Feb 03 '15 12:02

Colin Breame


3 Answers

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

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.

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.

like image 163
Bassem Reda Zohdy Avatar answered Nov 09 '22 10:11

Bassem Reda Zohdy


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

Hibernate NamingStrategy that follows Spring recommended naming conventions.

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_id column.

Related issue raised on Spring boot project

like image 41
Predrag Maric Avatar answered Nov 09 '22 10:11

Predrag Maric


Figured it out.

Use DefaultNamingStrategy and backticks in the @Column annotation.

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

and

@Column(name = "`datumId`")
private int datumId;
like image 30
postalservice14 Avatar answered Nov 09 '22 11:11

postalservice14