[增刪改查] 最規範的 JPA 多對多 CURD 示例
阿新 • • 發佈:2019-02-13
一、前言
資料庫中表多對多的關係也是很常見的,如一個許可權系統,設定的足夠嚴密,就是 許可權(選單)與角色多對多
關係,角色與使用者多對多
關係。
二、程式碼
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<StudentTeacher> getStudentTeacherByStudentId(Integer id);
/**
* 1.2、教師關聯查詢
* @param id
* @return
*/
@Query(value = "select * from t_st where teacher_id=?1", nativeQuery = true)
List<StudentTeacher> 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<StudentTeacher> 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<String, Object> map = new HashMap<String, Object>();
Student student = studentDao.findOne(id);
map.put("data", student);
//先斷絕來外
studentTeacherDao.deleteConnectionByStudentId(id);
//再剷除
studentDao.delete(id);
return student;
}
/**
* 5、全
* @return
*/
@GetMapping("/all")
public List<Student> 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<StudentTeacher> 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<String, Object> deleteTeacherById(@PathVariable Integer id) {
Map<String, Object> map = new HashMap<String, Object>();
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<Teacher> 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 介面
2、JPA 自動生成的資料庫表的關係
3、測試
學生查詢:輸入 id=1
①、輸入資料
②、輸出結果
四、小結
易錯點
1、使用 @Query
更新刪除時,同時要使用 @Modifying
、@Transaction