Spring - 配置Hibernate Jpa的问题

时间:2018-01-07 05:10:37

标签: java spring hibernate spring-mvc jpa

我从Spring Boot 1.5.9迁移到正常的Spring项目。

application.properties我已添加

spring.autoconfigure.exclude[0]=org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration
spring.autoconfigure.exclude[1]=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
spring.autoconfigure.exclude[2]=org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration
spring.autoconfigure.exclude[3]=org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration

我有一个配置类

@Configuration
public class HibernateJpaConfig {

private Map<String, String> properties = new HashMap<String, String>();

public HibernateJpaConfig() {
    properties.put("hibernate.hbm2ddl.auto", "create-drop");
}

@Bean
@Primary
public DataSource dataSource(){
    DataSource dataSource = new org.apache.tomcat.jdbc.pool.DataSource();
    dataSource.setDriverClassName("org.h2.Driver");
    dataSource.setUrl("jdbc:h2:mem:testdb");
    dataSource.setUsername("sa"); dataSource.setPassword("");
    return dataSource;
}

@Autowired
private DataSource dataSource;

@Autowired(required = false)
private PersistenceUnitManager persistenceUnitManager;

@Bean
public PlatformTransactionManager transactionManager() {
    return new JpaTransactionManager();
}

@Bean
public JpaVendorAdapter jpaVendorAdapter() {
    AbstractJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
    adapter.setShowSql(false);
    adapter.setDatabase(Database.H2);
    adapter.setDatabasePlatform("H2");
    adapter.setGenerateDdl(true);
    return adapter;
}

@Bean
public EntityManagerFactoryBuilder entityManagerFactoryBuilder(JpaVendorAdapter jpaVendorAdapter) {
    EntityManagerFactoryBuilder builder = new EntityManagerFactoryBuilder(
            jpaVendorAdapter, properties,
            this.persistenceUnitManager);
    builder.setCallback(null);
    return builder;
}

@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder factoryBuilder) {
    Map<String, Object> vendorProperties = new LinkedHashMap<String, Object>();
    vendorProperties.putAll(properties);

    return factoryBuilder.dataSource(this.dataSource).packages("com.fabio.springmvc.domain")
            .properties(vendorProperties).jta(false).build();
}

}

当我运行项目时,我遇到以下错误(我已添加警告,因为它似乎与问题相关)

    2018-01-07 06:03:34.542  WARN 17268 --- [  restartedMain] ationConfigEmbeddedWebApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [com/fabio/springmvc/config/HibernateJpaConfig.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory
2018-01-07 06:03:34.545  INFO 17268 --- [  restartedMain] o.apache.catalina.core.StandardService   : Stopping service [Tomcat]
2018-01-07 06:03:34.557  INFO 17268 --- [  restartedMain] utoConfigurationReportLoggingInitializer : 

Error starting ApplicationContext. To display the auto-configuration report re-run your application with 'debug' enabled.
2018-01-07 06:03:34.564 ERROR 17268 --- [  restartedMain] o.s.boot.SpringApplication               : Application startup failed

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [com/fabio/springmvc/config/HibernateJpaConfig.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1628) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1080) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:857) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122) ~[spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693) [spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360) [spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:303) [spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118) [spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107) [spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE]
at com.fabio.springmvc.SpringmvcApplication.main(SpringmvcApplication.java:17) [classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_121]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_121]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_121]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_121]
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) [spring-boot-devtools-1.5.9.RELEASE.jar:1.5.9.RELEASE]
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.persistenceException(EntityManagerFactoryBuilderImpl.java:954) ~[hibernate-entitymanager-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:882) ~[hibernate-entitymanager-5.0.12.Final.jar:5.0.12.Final]
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:60) ~[spring-orm-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:360) ~[spring-orm-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:382) ~[spring-orm-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:371) ~[spring-orm-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:336) ~[spring-orm-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1687) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1624) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
... 21 common frames omitted
Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: com.fabio.springmvc.domain.Customer column: addressLine1 (should be mapped with insert="false" update="false")
at org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:830) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.mapping.PersistentClass.checkPropertyColumnDuplication(PersistentClass.java:848) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.mapping.PersistentClass.checkPropertyColumnDuplication(PersistentClass.java:844) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:870) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:605) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.mapping.RootClass.validate(RootClass.java:265) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.boot.internal.MetadataImpl.validate(MetadataImpl.java:329) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:443) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:879) ~[hibernate-entitymanager-5.0.12.Final.jar:5.0.12.Final]
... 28 common frames omitted

配置类基于Spring boot 1.3的课程,这里我使用的是1.5.9,我不知道为什么会遇到这个问题。

编辑客户重复列

@Entity
public class Customer extends AbstractDomainClass{

private String firstName;
private String lastName;
private String email;
private String phoneNumber;
@Embedded
private Address billingAddress;
@Embedded
private Address shippingAddress;
// getters setters
}

地址类

@Embeddable
public class Address {

private String addressLine1;
private String addressLine2;
private String city;
private String state;
private String zipCode;
// getters setters
}

1 个答案:

答案 0 :(得分:2)

出现此问题是因为您具有以下映射:

@Entity
public class Customer extends AbstractDomainClass {
    //other attributes...
    @Embedded
    private Address billingAddress;
    @Embedded
    private Address shippingAddress;
}

在这里,Hibernate将尝试做的是在表的列中映射@Embedded类的属性。也就是说,它会将Address#addressLine1从属性Address billingAddress映射到表addressLine1中的列customer。属性billingAddress和类Address的其他字段也会发生类似情况。然后,它会对Address shippingAddress执行相同操作,也就是说,它会将Address#addressLine1的{​​{1}}映射到表shippingAddress中的列addressLine1。这是例外的原因。

由于这更像是设计问题,而不是代码中的问题,我建议采用一些方法来解决它。

  1. 在表格中为所有字段添加不同的列,并将每个列映射到类中的特定属性。这是一个基本的例子:

    你桌子的DDL(使用我能想到的最常见的sql)。

    customer

    使用CREATE TABLE customer ( id INT NOT NULL, billingAddressLine1 VARCHAR(200) NOT NULL, shippingAddressLine1 VARCHAR(200) NOT NULL, -- other columns... PRIMARY KEY(id) ); 的{​​{1}}属性的Hibernate映射:

    @Embedded
  2. 不使用@AttributeOverrides表中的列,而是使用名为@Entity public class Customer extends AbstractDomainClass { //other attributes... @Embedded @AttributeOverrides( @AttributeOverride( name = "addressLine1", column = @Column(name = "billingAddressLine1"), ) //do similar for the other attributes... ) private Address billingAddress; @Embedded @AttributeOverrides( @AttributeOverride( name = "addressLine1", column = @Column(name = "shippingAddressLine1") ) //do similar for the other attributes... ) private Address shippingAddress; } 的单独表和名为customer的列(或您喜欢的名称)来存储地址顾客。

    你桌子的DDL(使用我能想到的最常见的sql)。

    address

    类的Hibernate映射(不是addressType):

    CREATE TABLE customer (
        id INT NOT NULL,
        -- other columns...
        PRIMARY KEY(id)
    );
    
    CREATE TABLE address (
        id INT NOT NULL,
        addressType INT NOT NULL,
        customer_id INT NOT NULL,
        addressLine1 VARCHAR(200) NOT NULL,
        -- other columns...
        PRIMARY KEY(id),
        FOREIGN KEY (customer_id) REFERENCES customer(id)
    );