举一个例子来说明这个多对对的关系。
我们在选课过程中,一个学生可以选多门课。反过来一个课程会被多个人选。两边都会存在多对多的关系。
在JPA中就可以用
@ManyToMany
去解决,具体如下
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
package com.rumenz.lession16.controller.entity;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import java.util.Set;
/**
* @className: Student
* @description: TODO 类描述
* @author: 入门小站 rumenz.com
* @date: 2021/12/15
**/
@Getter
@Setter
@Entity
@Table(name="student")
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
@ManyToMany
@JoinTable(
name = "student_course",
joinColumns = @JoinColumn(name = "sid"),
inverseJoinColumns = @JoinColumn(name = "cid"))
Set<Course> likedCourses;
}
@ManyToMany
标注存在对对多的关系@JoinTable
定义数据库关系,joinColumns
属性链接自己,inverseJoinColumns
属性链接对方@JoinColumn
注解定义外键在使用@ManyToMany注解的时候,在输出实体类时,出现了java.lang.StackOverflowError报错,这个是因为在实体类中,使用了@Data注解,@Data注解中的@ToString会导致java.lang.StackOverflowError,需要重写
不能用lombok的@EqualsAndHashCode和@ToString,否则死循环内存溢出
package com.rumenz.lession16.controller.entity;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.*;
import javax.persistence.*;
import java.util.Set;
/**
* @className: Course
* @description: TODO 类描述
* @author: 入门小站 rumenz.com
* @date: 2021/12/15
**/
@Getter
@Setter
@Entity
@Table(name="course")
public class Course {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
@JsonIgnore
@ManyToMany(mappedBy = "likedCourses")
Set<Student> likes;
}
package com.rumenz.lession16.controller.entity;
import lombok.Data;
import javax.persistence.*;
/**
* @className: StudentCourse
* @description: TODO 类描述
* @author: 入门小站 rumenz.com
* @date: 2021/12/15
**/
@Data
@Entity
@Table(name="student_course")
public class StudentCourse {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private Integer sid;
private Integer cid;
private String rating;
}
数据库访问的ORM,也叫持久层,负责访问数据库。一般通过继承
JpaRepository
,CurdRepository
实现,这里声明的接口不必实现,只要遵循Jpa规范就可以自动生成。
package com.rumenz.lession16.controller.repository;
import com.rumenz.lession16.controller.entity.Student;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
/**
* @className: StudentRepository
* @description: TODO 类描述
* @author: 入门小站 rumenz.com
* @date: 2021/12/15
**/
@Repository
public interface StudentRepository extends CrudRepository<Student,Integer> {
}
package com.rumenz.lession16.controller.repository;
import com.rumenz.lession16.controller.entity.Course;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
/**
* @className: CourseRepository
* @description: TODO 类描述
* @author: 入门小站 rumenz.com
* @date: 2021/12/15
**/
@Repository
public interface CourseRepository extends CrudRepository<Course,Integer> {
}
package com.rumenz.lession16.controller.repository;
import com.rumenz.lession16.controller.entity.StudentCourse;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
/**
* @className: StudentCourseRepository
* @description: TODO 类描述
* @author: 入门小站 rumenz.com
* @date: 2021/12/15
**/
@Repository
public interface StudentCourseRepository extends CrudRepository<StudentCourse,Integer> {
}
业务层,负责调用
Repository
返回,处理数据
package com.rumenz.lession16.controller.service;
import com.rumenz.lession16.controller.entity.Student;
import java.util.List;
/**
* @className: UserService
* @description: TODO 类描述
* @author: 入门小站 rumenz.com
* @date: 2021/12/15
**/
public interface UserService {
List<Student> listStudent();
}
UserService接口的实现类
package com.rumenz.lession16.controller.service.Impl;
import com.rumenz.lession16.controller.entity.Student;
import com.rumenz.lession16.controller.repository.StudentRepository;
import com.rumenz.lession16.controller.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
/**
* @className: UserServiceImpl
* @description: TODO 类描述
* @author: 入门小站 rumenz.com
* @date: 2021/12/15
**/
@Service
public class UserServiceImpl implements UserService {
@Autowired
StudentRepository studentRepository;
@Override
public List<Student> listStudent() {
List<Student> list=new ArrayList<>();
Iterable<Student> res = studentRepository.findAll();
res.forEach(item->{
System.out.println(item.getLikedCourses().toString());
});
res.forEach(list::add);
return list;
}
}
控制器,负责接收前端请求,调用
service
返回数据。
package com.rumenz.lession16.controller;
import com.rumenz.lession16.controller.entity.Student;
import com.rumenz.lession16.controller.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* @className: RumenzController
* @description: TODO 类描述
* @author: 入门小站 rumenz.com
* @date: 2021/12/15
**/
@RestController
@RequestMapping("/rumenz")
public class RumenzController {
@Autowired
UserService userService;
//多对多查询
@GetMapping("/listStudent")
public List<Student> listStudent(){
return userService.listStudent();
}
}
本小结源码地址:
介绍