简体   繁体   English

春季-配置Hibernate Jpa的问题

[英]Spring - Issue configuring Hibernate Jpa

I'm moving from a Spring Boot 1.5.9 to a normal Spring project. 我正在从Spring Boot 1.5.9迁移到普通的Spring项目。

In application.properties I've added 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

I have a configuration class 我有一个配置类

@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();
}

}

When I run the project I have the following errors (I've added a warning since it seems pertinent to the issue) 运行项目时,出现以下错误(我添加了一个警告,因为它似乎与问题有关)

    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

The configuration class is based on a course with Spring boot 1.3, here I'm using 1.5.9, I don't get why I'm having this issue. 配置类基于Spring Boot 1.3的课程,这里我使用1.5.9,我不明白为什么会有这个问题。

Edit for customer repeated column 编辑客户重复栏

@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
}

Address class 地址类别

@Embeddable
public class Address {

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

The issue occurs because you have the following mapping: 发生此问题的原因是您具有以下映射:

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

Here, what Hibernate will try to do is to map the attributes of the @Embedded class in columns of your table. 在这里,Hibernate尝试做的是在表的列中映射@Embedded类的属性。 This is, it will map Address#addressLine1 from attribute Address billingAddress to the column addressLine1 in the table customer . Address#addressLine1 ,它将把Address#addressLine1从属性Address billingAddress到表customer addressLine1 Similar will happen with the other fields for attribute billingAddress and for class Address . 属性billingAddressAddress类的其他字段也会发生类似的情况。 And then, it will do the same with Address shippingAddress , this is, it will map Address#addressLine1 for shippingAddress to column addressLine1 in table customer . 然后,它将对Address shippingAddress进行相同的操作,即它将shippingAddress Address#addressLine1映射到表customer addressLine1列。 This is the cause of the exception. 这是导致异常的原因。

Since this is more a design problem rather than an issue in your code, I would suggest some ways to solve it. 由于这更多是设计问题,而不是代码中的问题,因此,我建议一些解决方法。

  1. Have different columns in your table for all the fields, and map each one to the specific attribute in classes. 表中的所有字段都有不同的列,并将每个字段映射到类中的特定属性。 Here's a basic example: 这是一个基本示例:

    DDL of your table (using the most common sql I can come up with). 表的DDL(使用我能想到的最常见的sql)。

     CREATE TABLE customer ( id INT NOT NULL, billingAddressLine1 VARCHAR(200) NOT NULL, shippingAddressLine1 VARCHAR(200) NOT NULL, -- other columns... PRIMARY KEY(id) ); 

    Hibernate mapping for @Embedded attributes using @AttributeOverrides : 使用@AttributeOverrides@Embedded属性进行休眠映射:

     @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; } 
  2. Instead of having the columns in the customer table, use a separate table called address and a column called addressType (or the name you prefer) to store addresses for a customer. 不要在customer表中包含这些列,而要使用一个单独的表(称为address和一个名为addressType (或您喜欢的名称)的列来存储客户的地址。

    DDL of your table (using the most common sql I can come up with). 表的DDL(使用我能想到的最常见的sql)。

     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) ); 

    Hibernate mapping for the classes (not @Embedded ): 类的Hibernate映射(不是@Embedded ):

     //@Embedded @Entity public class Address extends AbstractDomainClass { private String addressLine1; private String addressLine2; private String city; private String state; private String zipCode; //new fields... private int addressType; @ManyToOne private Customer customer; // getters and setters ... } @Entity public class Customer extends AbstractDomainClass { //other attributes... @OneToOne(mappedBy="customer", cascade=CascadeType.ALL) private Address billingAddress; @OneToOne(mappedBy="customer", cascade=CascadeType.ALL) private Address shippingAddress; //getters and setters... } 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM