1 概述 在本节课程中,我们继续学习多表关系,学习多对多关系。
在本例中,我们使用学生和课程个实体,一个学生可以学多门课程,一门课程可以被多个学生学。
同上一节一样,继续采用Spring Boot+Spring Data JPA。工程结构如下:
重点对象,两个实体。
2 实体 学生实体Student.java
package com.wangshenghua.entity;
import java.io.Serializable; import java.util.Set;
import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.Table; import javax.persistence.JoinColumn;
@Entity @Table(name = “student”) public class Student implements Serializable {
private static final long serialVersionUID = 2478074694454421216L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; private String name; @ManyToMany(cascade = CascadeType.ALL) @JoinTable(name = "student_has_course", joinColumns = @JoinColumn(name = "student_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "course_id", referencedColumnName = "id")) private Set<Course> courses; // @JoinTable参数里的 name 指向中间表 // joinColumns 当前实体ID // inverseJoinColumns对方实体ID public Student() { } public Student(String name) { super(); this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set<Course> getCourses() { return courses; } public void setCourses(Set<Course> courses) { this.courses = courses; } @Override public String toString() { return "Student [id=" + id + ", name=" + name + ", courses=" + courses + "]"; }} 课程实体Course.java
package com.wangshenghua.entity;
import java.io.Serializable; import java.util.Set;
import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.Table;
@Entity @Table(name = “course”) public class Course implements Serializable {
private static final long serialVersionUID = 5844590076435775458L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; private String name; @ManyToMany(cascade = CascadeType.ALL) @JoinTable(name = "student_has_course", joinColumns = @JoinColumn(name = "course_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "student_id", referencedColumnName = "id")) private Set<Student> students; // @JoinTable里的 name 中间表 // joinColumns 当前实体ID // inverseJoinColumns对方实体ID public Course() { } public Course(String name) { super(); this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set<Student> getStudents() { return students; } public void setStudents(Set<Student> students) { this.students = students; } @Override public String toString() { return "Course [id=" + id + ", name=" + name + ", students=" + students + "]"; }} 在对多对关系中,无论哪方看,都是多对多关系,关键是@ManyToMany注解,它有参数级联关系和关联关系。
我们重点说关联关系。@JoinTable注解关联一个表,参数里的 name 指向中间表,@JoinColumn注解将中间表和当前表的主键关联,inverseJoinColumns对方实体ID。
3 数据访问对象 Spring Data JPA的数据访问对象是接口,封装了很多细节。
略,具体参见源码。
4 驱动类 在驱动为中实例学生实体和课程课程,并实例数据访问对象,用于操作实体。
package com.wangshenghua.config;
import java.util.HashSet; import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.domain.EntityScan; import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import com.wangshenghua.dao.CourseRepository; import com.wangshenghua.dao.StudentRepository; import com.wangshenghua.entity.Course; import com.wangshenghua.entity.Student;
@SpringBootApplication @EnableJpaRepositories(basePackages = “com.wangshenghua.dao”) @EntityScan(basePackages = “com.wangshenghua.entity”) public class HibernateManyToManyMappingApplication implements CommandLineRunner {
@Autowired private StudentRepository studentRepository; @Autowired private CourseRepository courseRepository; public static void main(String[] args) { SpringApplication.run(HibernateManyToManyMappingApplication.class, args); } @Override public void run(String... args) throws Exception { Student hhc = new Student("候慧聪"); Student hl = new Student("黄林"); Course java = new Course("Java"); Course html = new Course("HTML"); Course spring = new Course("Spring"); Set<Course> sets = new HashSet<>(); sets.add(spring); sets.add(html); sets.add(java); hhc.setCourses(sets); Set<Course> sets2 = new HashSet<>(); sets2.add(html); sets2.add(java); hl.setCourses(sets2); //studentRepository.save(hhc); studentRepository.save(hl); }} 5 Spring boot配置 application.properties
spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/testdb?useUnicode=true&characterEncoding=UTF-8 spring.datasource.username=testdb spring.datasource.password=testdb
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect spring.jpa.hibernate.ddl-auto = update
logging.level.org.hibernate.SQL=DEBUG logging.level.org.hibernate.type=TRACE 6 相关依赖
<?xml version="1.0" encoding="UTF-8"?>4.0.0 org.springframework.boot spring-boot-starter-parent 2.1.6.RELEASE com.wangshenghua hibernate-many-to-many-mapping 0.0.1-SNAPSHOT hibernate-many-to-many-mapping Demo project for Spring Boot
<properties> <java.version>1.8</java.version> <maven-jar-plugin.version>3.1.1</maven-jar-plugin.version> </properties> <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.38</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> 7 总结 多表关系,特别要注意理清表之间的关系。共用图形工具梳理表关系,如MySQL Workbench,梳理后可以直观地认识实体之间关系。在Spring Data JPA创建表后,将表结构与 MySQL Workbench 建模图对比,看是否一致。
本节课程源码已经上传到github,可以前往下载。