一对多映射不起作用Spring数据JPA

Posted

技术标签:

【中文标题】一对多映射不起作用Spring数据JPA【英文标题】:One to Many mapping not working Spring data JPA 【发布时间】:2016-11-25 03:13:53 【问题描述】:

我正在使用 Spring 数据 JPA 进行持久化,并通过注释配置了 Spring。

1)Spring配置类

package com.karthik.config;

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSource;
import org.apache.log4j.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.karthik")
@EnableJpaRepositories("com.karthik.repository")
public class AppConfig 

    private static final Logger logger = Logger.getLogger(AppConfig.class);

    @Bean
    public DataSource dataSource() 
        BasicDataSource dataSource = new org.apache.commons.dbcp.BasicDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("**********");
        dataSource.setUsername("******");
        dataSource.setPassword("*****");
        logger.info("DATA SOURCE CONFIGURED");
        return dataSource;
    

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource, JpaVendorAdapter jpaVendorAdapter) 
        LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
        lef.setDataSource(dataSource);
        lef.setJpaVendorAdapter(jpaVendorAdapter);
        lef.setPackagesToScan("com.karthik");
        return lef;
    

    @Bean
    public JpaVendorAdapter jpaVendorAdapter() 
        HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
        hibernateJpaVendorAdapter.setShowSql(true);
        hibernateJpaVendorAdapter.setGenerateDdl(true);
        hibernateJpaVendorAdapter.setDatabase(Database.MYSQL);
        return hibernateJpaVendorAdapter;
    

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

2) 实体类

酒店和房间之间存在一对多映射

酒店实体

package com.karthik.entity;

import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@Entity
@Table(name="hotels")
public class HotelEntity 

    @Id
    @GeneratedValue
    @Column(name="mh_id")
    private Long id;

    @Column(name="mh_name", length=100, nullable=false)
    private String name;

    @Column(name="mh_description", length=500, nullable=false)
    private String description;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name="mh__created_on", nullable=false)
    private Date createdOn;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "hotelId")
    private Set<RoomEntity> rooms = new HashSet<>(0);

    public HotelEntity()
    

    //field getters and setters

房间实体

package com.karthik.entity;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;


@Entity
@Table(name="rooms")
public class RoomEntity 

    @Id
    @GeneratedValue
    @Column(name="mr_id")
    private Long id;

    @Column(name="mr_code", length=50)
    private String code;

    @Column(name="mr_roomtype_name", nullable=false, length=50)
    private String roomType;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "mr__hotelId", nullable = false)
    private Integer hotelId;

    public RoomEntity() 
    

    //field getters and setters

pom.xml

<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>$springframework.version</version>
    </dependency>
    <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.0.1</version>
            <scope>provided</scope>
    </dependency>
    <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-jpa</artifactId>
            <version>1.4.1.RELEASE</version>
    </dependency>
    <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>4.3.8.Final</version>
    </dependency>
    <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>1.2.2</version>
    </dependency>
    <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.27</version>
    </dependency>

当酒店和房间实体之间没有映射时,上面的代码可以正常工作。 但是添加映射时,部署本身时会出现错误。以下是我在控制台中看到的错误:

Nov 25, 2016 8:09:08 AM org.apache.catalina.core.StandardContext startInternal
SEVERE: One or more listeners failed to start. Full details will be found in the appropriate container log file
Nov 25, 2016 8:09:08 AM org.apache.catalina.core.StandardContext startInternal
SEVERE: Context [/services] startup failed due to previous errors

我在控制台中看不到任何异常/错误的根本原因,这使得调试变得困难。我只在控制台上看到一条 WARN 消息:

WARN: HHH015016: Encountered a deprecated javax.persistence.spi.PersistenceProvider [org.hibernate.ejb.HibernatePersistence]; use [org.hibernate.jpa.HibernatePersistenceProvider] instead.
Nov 25, 2016 7:53:34 AM org.hibernate.jpa.internal.util.LogHelper logPersistenceUnitInformation

1) 导致上述错误的映射有什么问题? 2) 如何在控制台捕获错误/异常堆栈跟踪? 3)弃用消息是什么意思?如何更改/更新持久性提供程序? 4)我需要使用不同的数据源(目前使用DBCP数据源)来支持映射吗?

请回答以上所有问题。

【问题讨论】:

【参考方案1】:

你的关系应该基于实体

在 RoomEntity 中

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "mr__hotelId", nullable = false)
private Hotel hotel;

酒店内

@OneToMany(fetch = FetchType.LAZY, mappedBy = "hotel")
private Set<RoomEntity> rooms = new HashSet<>(0);

【讨论】:

现在可以正常使用了。谢谢。如果您也可以回答问题,那将很有帮助。 4.【参考方案2】:

一般来说,数据库中的表之间的关系更有效。在这里,实体类被视为关系表(JPA 的概念)。

@Entity
@Table(name="hotels")
public class HotelEntity 
  .
  .
  .
  @OneToMany(fetch = FetchType.LAZY, mappedBy = "hotel")
  private Set<RoomEntity> rooms = new HashSet<>(0);
  .
  .
  .


@Entity
@Table(name="rooms")
public class RoomEntity 
 .
 .
 .
 @ManyToOne(fetch = FetchType.LAZY)
 @JoinColumn(name = "hotel_id", nullable = false)
 private Hotel hotel;
 .
 .
 .


由于在 JPA 规范中多对一(几乎)始终是双向关系的所有者,因此一对多关联由 @OneToMany(mappedBy=...) 注释

【讨论】:

谢谢。它现在工作正常。如果您也可以回答问题,那将很有帮助。 4.【参考方案3】:

org.hibernate.ejb.HibernatePersistence 类已弃用,并在 entityManagerFactory 方法中添加以下行。它解决了持久性提供程序问题。

 LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
 lef.setPersistenceProvider(new HibernatePersistenceProvider());

【讨论】:

它有效。谢谢。如果您也可以回答问题,那将很有帮助。 4.

以上是关于一对多映射不起作用Spring数据JPA的主要内容,如果未能解决你的问题,请参考以下文章

多行的spring数据jpa更新不起作用

带有 Hibernate 和 Ehcache 的 Spring 数据 JPA 不起作用

LEFT JOIN FETCH 不起作用 - Spring 数据 JPA

Java JPA双向ManyToOne映射不起作用

Spring Data JPA主键违规约束不起作用

Spring Boot JPA 连接验证不起作用