Jpa配置一對多關系


在網上查了很多關於jpa的一對多表關聯的操作,踩了很多坑,今天終於解決了

下面上一下我自己的代碼,記錄一下

老師和學生(一對多關系)

首先搭建環境,添加依賴包

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.lyf</groupId>
    <artifactId>one-to-more</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.22</version>
        </dependency>
    </dependencies>
</project>

編寫數據庫配置文件

spring.datasource.url=jdbc:mysql://localhost:3306/jpa?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=08186912
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.database=mysql

實體類

package com.lyf.pojo;

import lombok.Data;

import javax.persistence.*;

/**
 * @Date:2019-04-12
 * @Description:com.lyf.pojo
 * @version:1.0
 */
@Data
@Entity
@Table(name = "tb_student")
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "s_id")
    private Long sId;
    @Column(name = "s_name")
    private String sName;

    /**
     * 多個學生對應一個老師
     * 注解形式配置多對一
     *  1,配置表關系
     *  2,配置外鍵
     */
    @ManyToOne(targetEntity = Teacher.class)
    @JoinColumn(name = "s_t_id",referencedColumnName = "t_id")
    private Teacher teacher;
}

package com.lyf.pojo;

import lombok.Data;

import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;

/**
* @Date:2019-04-12
* @Description:教師和學生是一對多
*/
@Data
@Entity
@Table(name = "tb_teacher")
public class Teacher {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "t_id")
private Long tId;
@Column(name = "t_name")
private String tName;
//配置老師和學生一對多
/**
* 注解配置多表關系
* 1,聲名關系
* 2,配置外鍵,或者中間表
* OneToMany配置一對多
* targetEntity設置對應的實體類的類型
* JoinColumn 配置外鍵
* name:外鍵的名稱,
* referencedColumnName參照的主表的主鍵字段名稱
*/
@OneToMany(targetEntity = Student.class)
@JoinColumn(name = "s_t_id",referencedColumnName = "t_id")
private Set<Student> students = new HashSet<>();
}
 

springboot啟動類(引導類)

package com.lyf;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @Date:2019-04-12
 * @Description:com.lyf
 * @version:1.0
 */
@SpringBootApplication
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class,args);
    }
}

啟動引導類,查看數據庫會發現表生成成功

dao層代碼就不上了,繼承JpaRepository就行了

 

接下來我們進行保存操作

 

package com.lyf;

import com.lyf.dao.StudentDao;
import com.lyf.dao.TeacherDao;
import com.lyf.pojo.Student;
import com.lyf.pojo.Teacher;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * @Date:2019-04-12
 * @Description:com.lyf
 * @version:1.0
 */
@SpringBootTest
@RunWith(SpringRunner.class)
public class OneToMoreTest {

    @Autowired
    private TeacherDao teacherDao;
    @Autowired
    private StudentDao studentDao;
    @Test
    public void addTest(){
        Student student = new Student();
        student.setSName("老籃孩i");
        Teacher teacher = new Teacher();
        teacher.setTName("劉老師");
        //關聯學生和老師,添加學生信息時,還需添加外鍵的值
        student.setTeacher(teacher);


        studentDao.save(student);
        teacherDao.save(teacher);
    }
}

 

結果報錯了,發現我是先保存的學生信息,再保存的老師信息,此時數據庫中並沒有老師的信息,給學生關聯老師信息肯定是有問題的

報錯信息

 

org.springframework.dao.InvalidDataAccessApiUsageException: 
  org.hibernate.TransientPropertyValueException:
     object references an unsaved transient instance - save the transient instance before flushing : com.lyf.pojo.Student.teacher -> com.lyf.pojo.Teacher;
      nested exception is java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException:
        object references an unsaved transient instance - save the transient instance before flushing :
          com.lyf.pojo.Student.teacher -> com.lyf.pojo.Teacher

 學生表記錄插入了,老師表是空的

 

 

 

改成

 

package com.lyf;

import com.lyf.dao.StudentDao;
import com.lyf.dao.TeacherDao;
import com.lyf.pojo.Student;
import com.lyf.pojo.Teacher;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * @Date:2019-04-12
 * @Description:com.lyf
 * @version:1.0
 */
@SpringBootTest
@RunWith(SpringRunner.class)
public class OneToMoreTest {

    @Autowired
    private TeacherDao teacherDao;
    @Autowired
    private StudentDao studentDao;
    @Test
    public void addTest(){
        Student student = new Student();
        student.setSName("老籃孩i");
        Teacher teacher = new Teacher();
        teacher.setTName("劉老師");
        //關聯學生和老師,添加學生信息時,還需添加外鍵的值
        student.setTeacher(teacher);

        //要先保存主表信息
        teacherDao.save(teacher);
        studentDao.save(student);
    }
}

 控制台信息,很顯然成功了

Hibernate: alter table tb_student add constraint FKsojy7bicq68v21slcq9mtwtou foreign key (s_t_id) references tb_teacher (t_id)
2019-04-12 23:29:42.036  INFO 10980 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2019-04-12 23:29:42.748  INFO 10980 --- [           main] com.lyf.OneToMoreTest                    : Started OneToMoreTest in 7.77 seconds (JVM running for 9.806)
Hibernate: insert into tb_teacher (t_name) values (?)
Hibernate: insert into tb_student (s_name, s_t_id) values (?, ?)

查看數據庫也沒有問題

同樣我們通過Teacher表也能完成關聯操作,保存也是沒有問題的

@Test
    public void addTest1(){
        Student student = new Student();
        student.setSName("老籃孩i1");
        Teacher teacher = new Teacher();
        teacher.setTName("劉老師1");

        //通過主表來添加關聯
        teacher.getStudents().add(student);
        studentDao.save(student);
        teacherDao.save(teacher);
    }

 控制打印信息

Hibernate: insert into tb_student (s_name, s_t_id) values (?, ?)
Hibernate: insert into tb_teacher (t_name) values (?)
Hibernate: update tb_student set s_t_id=? where s_id=?

 

學生類和老師類都添加類外鍵的配置,都具備外鍵的維護,那么我們這里可以通過學生找到老師,也能通過老師找到學生,這是一種雙向關系

如果只配置一方,那就是單向的關系,只能通過指定的一方找到另一方

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM