[英]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
. 属性billingAddress
和Address
类的其他字段也会发生类似的情况。 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. 由于这更多是设计问题,而不是代码中的问题,因此,我建议一些解决方法。
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; }
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.