[增删改查] 最规范的 JPA 多对多 CURD 示例

一、前言

数据库中表多对多的关系也是很常见的,如一个权限系统,设置的足够严密,就是 权限(菜单)与角色多对多关系,角色与用户多对多关系。

二、代码

代码以及放到 github 上了:https://github.com/larger5/SpringBootJPAMM.git

1、代码结构

[增删改查] 最规范的 JPA 多对多 CURD 示例_第1张图片

省略了 Service 层

2、entity

① 学生

package com.cun.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "t_student")
public class Student {

    @Id
    @GeneratedValue
    private Integer id;

    @Column(length = 100)
    private String name;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Student() {
        super();
    }

}

② 教师

package com.cun.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "t_teacher")
public class Teacher {

    @Id
    @GeneratedValue
    private Integer id;

    @Column(length = 100)
    private String name;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Teacher() {
        super();
    }

}

③ 学生教师关系

package com.cun.entity;

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

@Entity
@Table(name = "t_st")
public class StudentTeacher {

    @Id
    @GeneratedValue
    private Integer id;

    @ManyToOne
    @JoinColumn(name="student_id")
    private Student student;

    @ManyToOne
    @JoinColumn(name="teacher_id")
    private Teacher teacher;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Student getStudent() {
        return student;
    }

    public void setStudent(Student student) {
        this.student = student;
    }

    public Teacher getTeacher() {
        return teacher;
    }

    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }

}

3、dao

① 学生

package com.cun.dao;

import org.springframework.data.jpa.repository.JpaRepository;

import com.cun.entity.Student;

public interface StudentDao extends JpaRepository<Student, Integer>{

}
② 教师
package com.cun.dao;

import org.springframework.data.jpa.repository.JpaRepository;

import com.cun.entity.Teacher;

public interface TeacherDao extends JpaRepository<Teacher, Integer>{

}

③ 学生教师关系

package com.cun.dao;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;

import com.cun.entity.StudentTeacher;

public interface StudentTeacherDao extends JpaRepository<StudentTeacher, Integer> {

    /**
     * 1.1、学生关联查询
     * @param id
     * @return
     */
    @Query(value = "select * from t_st where student_id=?1", nativeQuery = true)
    List getStudentTeacherByStudentId(Integer id);

    /**
     * 1.2、教师关联查询
     * @param id
     * @return
     */
    @Query(value = "select * from t_st where teacher_id=?1", nativeQuery = true)
    List getStudentTeacherByTeacherId(Integer id);


    /**
     * 2.1、通过教师 id 删除师生关系
     * ① 在 dao 层中加上 @Modifying
     * ② 注意添加 @Transactional,否则 TransactionRequiredException
     * ③ @Transactional 建议还是在 Service 层中加上,不要在 Controller 层中
     */
    @Modifying
    @Query(value="delete from t_st where teacher_id=?1",nativeQuery=true)
    void deleteConnectionByTeacherId(Integer teacherId);

    /**
     * 2.2、通过学生 id 删除师生关系
     * ① 在 dao 层中加上 @Modifying,否则 SQLException
     * ② 注意添加 @Transactional,否则 TransactionRequiredException
     * ③ @Transactional 建议还是在 Service 层中加上,不要在 Controller 层中
     */
    @Modifying
    @Query(value="delete from t_st where student_id=?1",nativeQuery=true)
    void deleteConnectionByStudentId(Integer studentId);

}

4、Controller

① 学生

package com.cun.controller;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.cun.dao.StudentDao;
import com.cun.dao.StudentTeacherDao;
import com.cun.entity.Student;
import com.cun.entity.StudentTeacher;

import springfox.documentation.swagger2.annotations.EnableSwagger2;

@RestController
@RequestMapping("/student")
@EnableSwagger2
@Transactional // 自定义update、delete、insert 的 Dao 接口必备
public class StudentController {

    @Autowired
    private StudentDao studentDao;

    @Autowired
    private StudentTeacherDao studentTeacherDao;

    /**
     * 1、查
     * ① 这个查的返回值应该是一个 List 集合
     * ② 一个学生可以有多个教师
     * ③ 使用关系表的 JPA 查询来完成
     * @param id
     * @return
     */
    @GetMapping("/get/{id}")
    public List getStudent(@PathVariable Integer id) {
        // return studentDao.findOne(id); //不符合实际需求的
        return studentTeacherDao.getStudentTeacherByStudentId(id);
    }

    /**
     * 2、增
     * @param student
     * @return
     */
    @PostMapping("insert")
    public Student insertStudent(Student student) {
        studentDao.save(student);

        // 保存后的 student 有 id
        return student;
    }

    /**
     * 3、改
     * @param student
     * @return
     */
    @PutMapping("/update")
    public Student updateStudent(Student student) {
        studentDao.save(student);
        return student;
    }

    /**
     * 4、删:
     * ① 删除前要判断是否存在关联关系,不同于一对多/多对一
     * ② 多对要先把关系删除掉,否则 ConstraintViolationException!
     * ③ 再把要删除的删掉,不会手下留情了!
     * ④ 注意添加 @Transactional,建议还是在 Service 层中加上,不要在 Controller 层中
     * @param id
     * @return
     */
    @DeleteMapping("/delete/{id}")
    public Student deleteStudent(@PathVariable Integer id) {
        Map map = new HashMap();
        Student student = studentDao.findOne(id);
        map.put("data", student);

        //先断绝来外
        studentTeacherDao.deleteConnectionByStudentId(id);

        //再铲除
        studentDao.delete(id);
        return student;
    }

    /**
     * 5、全
     * @return
     */
    @GetMapping("/all")
    public List getAllStudents() {
        return studentDao.findAll();
    }

}

② 教师

package com.cun.controller;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.cun.dao.StudentTeacherDao;
import com.cun.dao.TeacherDao;
import com.cun.entity.StudentTeacher;
import com.cun.entity.Teacher;

import springfox.documentation.swagger2.annotations.EnableSwagger2;

@RestController
@RequestMapping("/teacher")
@EnableSwagger2
@Transactional // 自定义update、delete、insert 的 Dao 接口必备
public class TeacherController {

    @Autowired
    private TeacherDao teacherDao;

    @Autowired
    private StudentTeacherDao studentTeacherDao;

    /**
     * 1、查
     * ① 这个查应该应该是一个 List 集合
     * ② 一个教师可以有多个学生
     * ③ 使用关系表的 JPA 查询来完成
     * @param id
     * @return
     */
    @GetMapping("/get/{id}")
    public List getTeacherById(@PathVariable Integer id) {
        // return teacherDao.findOne(id); //不符合实际需求的
        return studentTeacherDao.getStudentTeacherByTeacherId(id);
    }

    /**
     * 2、删:
     * ① 删除前要判断是否存在关联关系,不同于一对多/多对一
     * ② 多对要先把关系删除掉,否则 ConstraintViolationException!
     * ③ 再把要删除的删掉,不会手下留情了!
     * ④ 注意添加 @Transactional,建议还是在 Service 层中加上,不要在 Controller 层中
     * @param id
     * @return
     */
    @DeleteMapping("/delete/{id}")
    public Map deleteTeacherById(@PathVariable Integer id) {
        Map map = new HashMap();
        Teacher teacher = teacherDao.findOne(id);
        map.put("data", teacher);

        //先断绝来外
        studentTeacherDao.deleteConnectionByTeacherId(id);

        //再铲除
        teacherDao.delete(id);
        return map;
    }

    /**
     * 3、改
     * @param teacher
     * @return
     */
    @PutMapping("/update")
    public Teacher updateTeacher(Teacher teacher) {
        teacherDao.save(teacher);
        return teacher;
    }

    /**
     * 4、增
     * @param teacher
     * @return
     */
    @PostMapping("/insert")
    public Teacher insertTeacher(Teacher teacher) {
        teacherDao.save(teacher);
        // save 后 teacher 有 id 了
        return teacher;
    }

    /**
     * 5、全
     * @return
     */
    @GetMapping("/all")
    public List getAllTeachers() {
        return teacherDao.findAll();
    }

}

5、pom

加入 JPA、MySQL、Web

6、yml

server:
  port: 80 #为了以后访问项目不用写端口号
  context-path: / #为了以后访问项目不用写项目名
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=utf-8  #解决中文乱码的问题
    username: root
    password: 123
  jpa: 
    hibernate:
      ddl-auto: update  #数据库同步代码
    show-sql: true      #dao操作时,显示sql语句

三、其他

1、Swagger 接口

[增删改查] 最规范的 JPA 多对多 CURD 示例_第2张图片

2、JPA 自动生成的数据库表的关系

[增删改查] 最规范的 JPA 多对多 CURD 示例_第3张图片

3、测试

 学生查询:输入 id=1

①、输入数据

[增删改查] 最规范的 JPA 多对多 CURD 示例_第4张图片

②、输出结果

[增删改查] 最规范的 JPA 多对多 CURD 示例_第5张图片

四、小结

易错点

1、使用 @Query 更新删除时,同时要使用 @Modifying@Transaction

你可能感兴趣的:([增删改查] 最规范的 JPA 多对多 CURD 示例)