#項目埠的常用配置
server.port=8081
# 資料庫連接的配置
spring.datasource.url=jdbc:mysql:///jpa?useSSL=false
spring.datasource.username=root
spring.datasource.password=zempty123
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#資料庫連接池的配置,hikari 連接池的配置
spring.datasource.hikari.idle-timeout=30000
spring.datasource.hikari.connection-timeout=10000
spring.datasource.hikari.maximum-pool-size=15
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.auto-commit=true
#通過 jpa 自動生成資料庫中的表
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
@Setter
@Getter
@Accessors(chain = true)
@Entity(name = "stu")
//@Table
public class Student {
@Id
@GeneratedValue(strategy= GenerationType.TABLE)
private long id; @Column(length = 100)
private String name;
@Transient
private String test;
private int age;
private LocalTime onDuty;
private LocalDate onPosition;
private LocalDateTime birthdayTime;
}
學生實體類如下:
@Setter
@Getter
@Accessors(chain = true)
@Entity(name = "stu")
public class Student {
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
private long id;
@Column(length = 100)
private String name;
// 這裡是定義學生和課桌的一對一的關係
@OneToOne
// 下面的這個註解用來生成第三張表,來維護學生和課桌的關係
@JoinTable( name = "stu_desk",joinColumns = @JoinColumn(name="student_id"),inverseJoinColumns = @JoinColumn(name="desk_id") )
private Desk desk;
@Transient
private String test;
private int age;
private LocalTime onDuty;
private LocalDate onPosition;
private LocalDateTime birthdayTime;
}
@Setter
@Getter
@Accessors(chain = true)
@Entity
public class Desk {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private Integer deskNum;
@OneToOne(mappedBy = "desk")
private Student student;
}
@Setter
@Getter
@Accessors(chain = true)
@Entity(name="class_room")
public class ClassRoom {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
@OneToMany(mappedBy = "classRoom")
private Set<Student> students;
}
@ManyToOne
private ClassRoom classRoom;
@Setter
@Getter
@Accessors(chain = true)
@Entity
public class Teacher {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private String subject;
@ManyToMany(mappedBy = "teachers")
private Set<Student> students;
}
@ManyToMany
@JoinTable(name="stu_teacher",joinColumns = @JoinColumn(name ="stu_id"),inverseJoinColumns = @JoinColumn(name="teacher_id"))
private Set<Teacher> teachers;
// 設置級聯保存,保存學生的時候也會保存課桌
@OneToOne(cascade = CascadeType.PERSIST)
@JoinTable( name = "stu_desk",joinColumns = @JoinColumn(name="student_id"),inverseJoinColumns = @JoinColumn(name="desk_id") )
private Desk desk;
@PostMapping("/save_student")
public Student saveStudent() {
Student student = new Student()
.setAge(19)
.setName("zempty");
Desk desk = new Desk()
.setDeskNum(10);
// 學生分配座位,如果設置了級聯保存,保存學生的時候也會保存座位,如果沒設置級聯保存,添加課桌會報錯
student.setDesk(desk);
return studentRepository.save(student);
}
//設置級聯更新,在跟新 student 的時候如果更新 classroom , 會級聯更新 classroom
@ManyToOne(cascade = CascadeType.MERGE)
private ClassRoom classRoom;
@PutMapping("/update_student/{id}")
public Student updateStudent(@PathVariable("id") Integer id) {
Optional<Student> optional = studentRepository.findById(id);
optional.ifPresent(student->{
student.setName("zempty_zhao");
ClassRoom room = student.getClassRoom();
room.setName("IT 666999");
studentRepository.save(student);
});
return optional.get();
}
//設置級聯刪除操作,這是多對對的級聯刪除,
// 刪除學生的同時會刪除關聯的老師,如果老師還有關聯其他的學生,就會報錯,除非老師類也要級聯刪除,這個刪除是要慎重的
@ManyToMany(cascade = {CascadeType.REMOVE})
@JoinTable(name="stu_teacher",joinColumns = @JoinColumn(name = "stu_id"),inverseJoinColumns = @JoinColumn(name="teacher_id"))
private Set<Teacher> teachers;
@DeleteMapping("/delete_student/{id}")
public void deleteStudent(@PathVariable("id") Integer id) {
Optional<Student> optional = studentRepository.findById(id);
optional.ifPresent(student -> {
studentRepository.delete(student);
});
}
@OneToMany(mappedBy = "classRoom")
@JsonIgnore
private Set<Student> students;
@DeleteMapping("delete_room/{id}")
public void deleteClassRoom(@PathVariable("id") Integer id) {
Optional<ClassRoom> optional= classRoomRepository.findById(id);
optional.ifPresent(classRoom ->{
// 先找到所有的學生,把教室置空,然後刪除教室
Set<Student> students = classRoom.getStudents();
students.forEach(student -> student.setClassRoom(null));
classRoomRepository.delete(classRoom);
});;
}
@OneToMany(mappedBy = "classRoom",orphanRemoval = true)
@JsonIgnore
private Set<Student> students;
@DeleteMapping("delete_room/{id}")
public void deleteClassRoom(@PathVariable("id") Integer id) {
Optional<ClassRoom> optional= classRoomRepository.findById(id);
optional.ifPresent(classRoom ->{
// 先找到所有的學生,把教室置空,然後刪除教室
// Set<Student> students = classRoom.getStudents();
// students.forEach(student -> student.setClassRoom(null));
classRoomRepository.delete(classRoom);
});;
}
@OneToMany(mappedBy = "classRoom",cascade = CascadeType.PERSIST)
@JsonIgnore
private Set<Student> students;
@PostMapping("/save_room")
public ClassRoom saveClassRoom() {
ClassRoom room = new ClassRoom()
.setName("IT 教室");
Set<Student> students = new HashSet<>();
Student student = new Student().setName("test123");
students.add(student);
room.setStudents(students);
return classRoomRepository.save(room);
}
@PostMapping("/save_room")
public ClassRoom saveClassRoom() {
ClassRoom room = new ClassRoom()
.setName("IT 教室");
Set<Student> students = new HashSet<>();
Student stu = new Student().setName("test123");
students.add(stu);
//改進代碼,學生類維護關係,把教室設置到每一個學生當中
students.forEach(student -> student.setClassRoom(room));
room.setStudents(students);
return classRoomRepository.save(room);
}
public interface StudentRepository extends JpaRepository<Student,Integer> {
}
public interface StudentRepository extends JpaRepository<Student,Integer> {
// 查詢資料庫中指定名字的學生
List<Student> findByName(String name);
// 根據名字和年齡查詢學生
List<Student> getByNameAndAge(String name, Integer age);
//刪除指定名字的學生
Long deleteByName(String name);
// 統計指定名字學生的數量
Long countByName(String name);
}
//通過find 關鍵字進行名字查詢
@GetMapping("/find/{name}")
public List<Student> findStudentsByName(@PathVariable("name") String name) {
return studentRepository.findByName(name);
}
@GetMapping("/get/{name}/{age}")
public List<Student> getStudentByNameAndAge(@PathVariable("name") String name,@PathVariable("age") Integer age) {
return studentRepository.getByNameAndAge(name, age);
}
//根據名字進行刪除操作
@DeleteMapping("/delete/{name}")
//刪除的時候一定要添加事務註解
@Transactional
public Long deleteStudentByName(@PathVariable("name") String name) {
return studentRepository.deleteByName(name);
}
@GetMapping("/count/{name}")
public Long countStudentByName(@PathVariable("name") String name) {
return studentRepository.countByName(name);
}
public interface ClassRoomRepository extends JpaRepository<ClassRoom,Integer> {
//使用的 JPQL 的 sql 形式 from 後面是類名
// ?1 代表是的是方法中的第一個參數
@Query("select s from ClassRoom s where s.name =?1")
List<ClassRoom> findClassRoom1(String name);
//這是使用正常的 sql 語句去查詢
// :name 是通過 @Param 註解去確定的
@Query(nativeQuery = true,value = "select * from class_room c where c.name =:name")
List<ClassRoom> findClassRoom2(@Param("name")String name);
}
public interface TeacherRepositoty extends JpaRepository<Teacher,Integer> {
// 正常使用,只是多加了一個 sort 參數而已
@Query("select t from Teacher t where t.subject = ?1")
List<Teacher> getTeachers(String subject, Sort sort);
}
@GetMapping("/sort/{subject}")
public List<Teacher> getTeachers(@PathVariable("subject") String subject) {
// 第一種方法實例化出 Sort 類,根據年齡進行升序排列
Sort sort1 = Sort.by(Sort.Direction.ASC, "age");
//定義多個欄位的排序
Sort sort2 = Sort.by(Sort.Direction.DESC, "id", "age");
// 通過實例化 Sort.Order 來排序多個欄位
List<Sort.Order> orders = new ArrayList<>();
Sort.Order order1 = new Sort.Order(Sort.Direction.DESC, "id");
Sort.Order order2 = new Sort.Order(Sort.Direction.DESC, "age");
orders.add(order1);
orders.add(order2);
Sort sort3 = Sort.by(orders);
//可以傳不同的 sort1,2,3 去測試效果
return teacherRepositoty.getTeachers(subject, sort1);
}
public interface TeacherRepositoty extends JpaRepository<Teacher,Integer> {
//正常使用,只是多加了一個 Pageable 參數而已
@Query("select t from Teacher t where t.subject = :subject")
Page<Teacher> getPage(@Param("subject") String subject, Pageable pageable);
}
@GetMapping("page/{subject}")
public Page<Teacher> getPage(@PathVariable("subject") String subject) {
// 第一種方法實例化 Pageable
Pageable pageable1 = PageRequest.of(1, 2);
//第二種實例化 Pageable
Sort sort = Sort.by(Sort.Direction.ASC, "age");
Pageable pageable2 = PageRequest.of(1, 2, sort);
//第三種實例化 Pageable
Pageable pageable3 = PageRequest.of(1, 2, Sort.Direction.DESC, "age");
//可以傳入不同的 Pageable,測試效果
Page page = teacherRepositoty.getPage(subject, pageable3);
System.out.println(page.getTotalElements());
System.out.println(page.getTotalPages());
System.out.println(page.hasNext());
System.out.println(page.hasPrevious());
System.out.println(page.getNumberOfElements());
System.out.println(page.getSize());
return page;
}
public interface TeacherRepositoty extends JpaRepository<Teacher,Integer> , JpaSpecificationExecutor {
}
public interface JpaSpecificationExecutor<T> {
Optional<T> findOne(@Nullable Specification<T> var1);
List<T> findAll(@Nullable Specification<T> var1);
Page<T> findAll(@Nullable Specification<T> var1, Pageable var2);
List<T> findAll(@Nullable Specification<T> var1, Sort var2);
long count(@Nullable Specification<T> var1);
}
Predicate toPredicate(Root<T> var1, CriteriaQuery<?> var2, CriteriaBuilder var3);
實現該方法我們不需要弄清楚 Predicate , Root , CriteriaQuery 和 CriteriaBuilder 四個類的使用規則:現在有這樣的一條 sql 語句 :select * from teacher where age > 20Predicate 是用來建立 where 後的查尋條件的相當於上述sql語句的 age > 20。Root 使用來定位具體的查詢欄位,比如 root.get(「age」) ,定位 age欄位,CriteriaBuilder是用來構建一個欄位的範圍,相當於 > ,= ,<,and …. 等等CriteriaQuery 可以用來構建整個 sql 語句,可以指定sql 語句中的 select 後的查詢欄位,也可以拼接 where , groupby 和 having 等複雜語句。上面的分析是十分抽象的,關於這四個類的詳細使用,自己也可以上網查詢多參考幾個案例分析即可。 @GetMapping("/specification/{subject}")
public List<Teacher> specification(@PathVariable("subject") String subject) {
//實例化 Specification 類
Specification specification = ((root, criteriaQuery, criteriaBuilder) -> {
// 構建查詢條件
Predicate predicate = criteriaBuilder.equal(root.get("subject"), subject);
// 使用 and 連接上一個條件
predicate = criteriaBuilder.and(predicate, criteriaBuilder.greaterThan(root.get("age"), 21));
return predicate;
});
//使用查詢
return teacherRepositoty.findAll(specification);
}
public interface TeacherProjection {
String getName();
Integer getAge();
@Value("#{target.name +' and age is' + target.age}")
String getTotal();
}
public interface TeacherRepositoty extends JpaRepository<Teacher,Integer>, JpaSpecificationExecutor {
// 返回 TeacherProjection 接口類型的數據
@Query("select t from Teacher t ")
List<TeacherProjection> getTeacherNameAndAge();
}
@GetMapping("/projection")
public List<TeacherProjection> projection() {
// 返回指定欄位的數據
List<TeacherProjection> projections = teacherRepositoty.getTeacherNameAndAge();
// 列印欄位值
projections.forEach(teacherProjection -> {
System.out.println(teacherProjection.getAge());
System.out.println(teacherProjection.getName());
System.out.println(teacherProjection.getTotal());
});
return projections;
}