Hibernate、Spring 框架和多对多

Posted

技术标签:

【中文标题】Hibernate、Spring 框架和多对多【英文标题】:Hibernate, Spring framework and many-to-many 【发布时间】:2020-04-26 01:47:28 【问题描述】:

您能否帮我举一个使用 Spring(framework NOT BOOT OR MVC)和 Hibernate 的多对多关系的简单示例。我有两个类用户和课程,我需要一个中间表(类)用户课程。我不能使用 @ManyToMany 注释,因为我需要在中间表中添加额外的列,所以我需要在这个示例中执行类似的操作: https://examples.javacodegeeks.com/enterprise-java/hibernate/hibernate-many-to-many-relationship-with-join-table-example/ 您能否解释一下如何将弹簧包括在内。我尝试了一些东西,但收到了这个错误:

警告:上下文初始化期间遇到异常 - 取消刷新尝试:org.springframework.beans.factory.UnsatisfiedDependencyException:创建名称为“cursDAOImpl”的 bean 时出错:通过字段“sessionFactory”表示不满足的依赖关系;嵌套异常是 org.springframework.beans.factory.BeanCreationException:在类路径资源 [spring.xml] 中定义名称为“sessionFactory”的 bean 创建错误:调用 init 方法失败;嵌套异常是 org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: com.proiect.persistence.entity.UserCurs.pk.curs in com.proiect.persistence.entity.Curs.usercurs 线程“主”org.springframework.beans.factory.UnsatisfiedDependencyException 中的异常:创建名称为“cursDAOImpl”的 bean 时出错:通过字段“sessionFactory”表示不满足的依赖关系;嵌套异常是 org.springframework.beans.factory.BeanCreationException:在类路径资源 [spring.xml] 中定义名称为“sessionFactory”的 bean 创建错误:调用 init 方法失败;嵌套异常是 org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: com.proiect.persistence.entity.UserCurs.pk.curs in com.proiect.persistence.entity.Curs.usercurs 在 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:586) 在 org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87) 在 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:364) 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1269) 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:551) 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:481) 在 org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:312) 在 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) 在 org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:308) 在 org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) 在 org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761) 在 org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867) 在 org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543) 在 org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:139) 在 org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:83) 在 Application.main(Application.java:23) 原因:org.springframework.beans.factory.BeanCreationException:在类路径资源 [spring.xml] 中定义名称为“sessionFactory”的 bean 创建错误:调用 init 方法失败;嵌套异常是 org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: com.proiect.persistence.entity.UserCurs.pk.curs in com.proiect.persistence.entity.Curs.usercurs 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1631) 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553) 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:481) 在 org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:312) 在 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) 在 org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:308) 在 org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) 在 org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:208) 在 org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1136) 在 org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1064) 在 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:583) ... 15 更多 引起:org.hibernate.AnnotationException:mappedBy 引用了一个未知的目标实体属性:com.proiect.persistence.entity.Curs.usercurs 中的 com.proiect.persistence.entity.UserCurs.pk.curs 在 org.hibernate.cfg.annotations.CollectionBinder.bindStarToManySecondPass(CollectionBinder.java:768) 在 org.hibernate.cfg.annotations.CollectionBinder$1.secondPass(CollectionBinder.java:728) 在 org.hibernate.cfg.CollectionSecondPass.doSecondPass(CollectionSecondPass.java:70) 在 org.hibernate.cfg.Configuration.originalSecondPassCompile(Configuration.java:1695) 在 org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1424) 在 org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1844) 在 org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1928) 在 org.springframework.orm.hibernate4.LocalSessionFactoryBuilder.buildSessionFactory(LocalSessionFactoryBuilder.java:372) 在 org.springframework.orm.hibernate4.LocalSessionFactoryBean.buildSessionFactory(LocalSessionFactoryBean.java:454) 在 org.springframework.orm.hibernate4.LocalSessionFactoryBean.afterPropertiesSet(LocalSessionFactoryBean.java:439) 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1689) 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1627) ... 25 更多

@Entity
@Table(name="user")
public class User implements java.io.Serializable 

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer user_id;

    @Column(name="username")
    private String username;

    @Column(name="firstname")
    private String firstname;

    @Column(name="lastname")
    private String lastname;

    @Column(name="password")
    private String password;

    @Column(name="email")
    private String email;


    @OneToMany(fetch = FetchType.LAZY,mappedBy = "pk.user",cascade = CascadeType.DETACH, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.PERSIST)
    private Set<UserCurs> usercurs = new HashSet<UserCurs>(); 

    public Integer getUser_id() 
        return user_id;
    

    public void setUser_id(Integer user_id) 
        this.user_id = user_id;
    

    public String getUsername() 
        return username;
    


    public void setUsername(String username) 
        this.username = username;
    


    public String getFirstname() 
        return firstname;
    

    public void setFirstname(String firstname) 
        this.firstname = firstname;
    

    public String getLastname() 
        return lastname;
    

    public void setLastname(String lastname) 
        this.lastname = lastname;
    

    public String getPassword() 
        return password;
    

    public void setPassword(String password) 
        this.password = password;
    

    public String getEmail() 
        return email;
    

    public void setEmail(String email) 
        this.email = email;
    


    public Set<UserCurs> getUsercurs() 
        return usercurs;
    

    public void setUsercurs(Set<UserCurs> usercurs) 
        this.usercurs = usercurs;
    

这是我的课程实体

        package com.proiect.persistence.entity;

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

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;


@Entity
@Table(name = "curs")
public class Curs implements java.io.Serializable 

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer curs_id;

    @Column(name = "denumire")
    private String denumire;


    @OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.curs")
    private Set<UserCurs> usercurs = new HashSet<UserCurs>();

    public Curs() 
    

    public Curs(String denumire) 
        this.denumire = denumire;
    



    public Integer getCurs_id() 
        return curs_id;
    

    public void setCurs_id(Integer curs_id) 
        this.curs_id = curs_id;
    

    public String getDenumire() 
        return denumire;
    

    public void setDenumire(String denumire) 
        this.denumire = denumire;
    

    public Set<UserCurs> getUsercurs() 
        return usercurs;
    


    public void setUsercurs(Set<UserCurs> usercurs) 
        this.usercurs = usercurs;
    

    @Override
    public String toString() 
        return "Curs [curs_id=" + curs_id + ", denumire=" + denumire + ", usercurs=" + usercurs + "]";
    



然后我尝试通过 UserCurs 连接这些类

package com.proiect.persistence.entity;

import java.beans.Transient;

import javax.persistence.AssociationOverride;
import javax.persistence.AssociationOverrides;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.Table;

@Entity
@Table(name="user_curs")
@AssociationOverrides(
    @AssociationOverride(name="pk.user", joinColumns = @JoinColumn(name="user_id")),
    @AssociationOverride(name="pk.curs", joinColumns = @JoinColumn(name="curs_id"))
)
public class UserCurs implements java.io.Serializable 

    private static final long serialVersionUID = 4050660680047579957L;

    private UserCursID pk = new UserCursID();

    @EmbeddedId
    public UserCursID getPk() 
        return pk;
    

    @Transient
    public User getUser() 
        return getPk().getUser();
    

    public void setUser(User user) 
        getPk().setUser(user);
    

    @Transient
    public Curs getCs() 
        return getPk().getCs();
    

    public void setCs(Curs c) 
        getPk().setCs(c);
    

    public void setPk(UserCursID pk) 
        this.pk = pk;
    


用户CursID:

package com.proiect.persistence.entity;

import javax.persistence.Embeddable;
import javax.persistence.ManyToOne;

@Embeddable
public class UserCursID implements java.io.Serializable 

    private static final long serialVersionUID = -9120607274421816301L;

    @ManyToOne
    private User user;
    @ManyToOne
    private Curs cs;

    public User getUser() 
        return user;
    
    public void setUser(User user) 
        this.user = user;
    
    public Curs getCs() 
        return cs;
    
    public void setCs(Curs cs) 
        this.cs = cs;
       


这是我的 spring.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.3.xsd ">


    <context:property-placeholder
        location="classpath:database.properties" />

    <context:component-scan
        base-package="com.proiect.persistence.dao"></context:component-scan>
    <tx:annotation-driven />


    <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName"
            value="$jdbc.driverClassName" />
        <property name="url" value="$jdbc.url" />
        <property name="username" value="$jdbc.username" />
        <property name="password" value="$jdbc.password" />
    </bean>


    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="packagesToScan">
            <list>
                <value>com.proiect.persistence.entity</value>
            </list>
        </property>

        <property name="annotatedClasses">
            <list>

            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">$hibernate.dialect</prop>
                <prop key="hibernate.show_sql">$hibernate.show_sql:true</prop>
                <prop key="hibernate.format_sql">$hibernate.format_sql:false</prop>
                <prop key="hibernate.hbm2ddl.auto">create</prop>

            </props>
        </property>
    </bean>



    <bean id="transactionManager"
        class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <tx:annotation-driven />

    <bean id="persistenceExceptionTranslationPostProcessor"
        class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />

</beans>

【问题讨论】:

【参考方案1】:

第一个建议是名称属性之间的映射不正确,即

@AssociationOverrides(
    @AssociationOverride(name="pk.user", joinColumns = @JoinColumn(name="user_id")),
    @AssociationOverride(name="pk.curs", joinColumns = @JoinColumn(name="curs_id"))
)

您覆盖 pk.curs 的关系,该关系必须对应于 UserCursID 类的字段 curs 的名称。但是你有

@ManyToOne
    private Curs cs;

尽量让它们保持一致。

【讨论】:

以上是关于Hibernate、Spring 框架和多对多的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate框架之路多对多多关系

Spring Boot with hibernate:创建复合键和多对多关系

Hibernate框架进阶(中篇)之多表关系

Hibernate中一对多和多对一关系

三大框架 之 Hibernate查询(一对多多对多查询关系)

hibernate的一对多和多对一关联