前言:
现在直接操作数据库广泛使用的就是Mybatis和JPA.两种技术都是很好用的,但是相信使用过JPA的人都很清楚,jpa比较mybatis而言,无论是自动创建表单还是可直接调用的操作数据库的方法,都是mybatis所没有的。
在网上看到不少前辈的文章,本文不在做过多的JPA相关讲解,着重于JPA的应用。JPA的参考资料以及学习视频已经在本篇文章的第二部分给出相关链接。
一、什么是JPA
JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。
二、JPA的参考资料
- spring boot 中使用 jpa以及jpa介绍:https://blog.csdn.net/wujiaqi0921/article/details/78789087
- JPA之常用 基本注解:https://www.cnblogs.com/a8457013/p/7753575.html
- JPA @Basic 注解:http://fanlychie.github.io/post/jpa-basic-annotation.html
- JPA的Basic注解:http://www.voidcn.com/article/p-ficnnwzf-bbe.html
- Hibernate,JPA注解@EmbeddedId:https://www.cnblogs.com/xiluhua/p/4382062.html
- JPA实体标识的自动生成@ SequenceGenerator @GeneratedValue:https://blog.csdn.net/langjian2012/article/details/38894195
- 【JPA】对象关系映射_访问模式(ACCESS_TYPE(field|Property)):https://blog.csdn.net/jinghua7/article/details/21455727
- JPA官网:https://blog.csdn.net/weixin_41244495/article/details/88384799
- JPA、Hibernate、Spring data jpa之间的关系,终于明白了:https://my.oschina.net/u/3080373/blog/1828589
- JPA中@Access注解小结:https://my.oschina.net/u/1156626/blog/1619239?utm_medium=referral
- JPA中@JoinTable和@JoinColumn注解的使用:https://blog.csdn.net/yu870646595/article/details/51064634
- JPA 唯一约束条件@UniqueConstraint注解在Oracle失效问题(数据库表名字段名长度问题):https://blog.csdn.net/weixin_42142057/article/details/100573260
- JPA注解添加唯一约束:https://blog.csdn.net/qq_38705025/article/details/86636818
- Java中的@UniqueConstraint注释:https://www.javaroad.cn/articles/1265
- 视频:https://www.bilibili.com/video/BV1hE411s72B?from=search&seid=6182882383637815756
三、JPA的应用
3.1 项目结构
3.2 pom.xml以及application.properties
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>jpa_study</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>jpa_study</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</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>
</project>
server.port=8989
spring.datasource.platform=postgres
spring.datasource.url=jdbc:postgresql://127.0.0.1:5432/student
spring.datasource.username=postgres
spring.datasource.password=root
spring.datasource.driverClassName=org.postgresql.Driver
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults=false
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQL9Dialect
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
3.3 实体类
package com.example.jpa_study.controller.param;
public class StudentParam {
private String name;
private String address;
private Integer pageNo;
private Integer pageSize;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Integer getPageNo() {
return pageNo;
}
public void setPageNo(Integer pageNo) {
this.pageNo = pageNo;
}
public Integer getPageSize() {
return pageSize;
}
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
}
package com.example.jpa_study.controller.vo;
import java.util.List;
public class PageData<T> {
private List<T> list;
private long total;
public List<T> getList() {
return list;
}
public void setList(List<T> list) {
this.list = list;
}
public long getTotal() {
return total;
}
public void setTotal(long total) {
this.total = total;
}
}
package com.example.jpa_study.repository.entity;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.UpdateTimestamp;
import javax.persistence.*;
import java.util.Date;
@Table(name = "tb_student_info")
@Entity
public class Student {
/**
* 主键id
*/
private String id;
/**
* 学生姓名
*/
private String name;
/**
* 学生年龄 不放入数据库中
*/
private Integer age;
/**
* 出生年月日
*/
private Date birthDay;
/**
* 家庭住址
*/
private String address;
/**
* 创建时间
*/
private Date createTime;
/**
* 更新时间
*/
private Date updateTime;
@Id
@GeneratedValue(strategy = GenerationType.AUTO, generator = "uuid")
@GenericGenerator(name = "uuid", strategy = "uuid2")
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Column(name = "stu_name", length = 20, nullable = false)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Transient
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Temporal(TemporalType.DATE)
public Date getBirthDay() {
return birthDay;
}
public void setBirthDay(Date birthDay) {
this.birthDay = birthDay;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@CreationTimestamp
@Temporal(TemporalType.TIMESTAMP)
public Date getCreateTime() {
if (createTime != null) {
return (Date) createTime.clone();
}
return null;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime == null ? null : (Date) createTime.clone();
}
@UpdateTimestamp
@Temporal(TemporalType.TIMESTAMP)
public Date getUpdateTime() {
if (updateTime != null) {
return (Date) updateTime.clone();
}
return null;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime == null ? null : (Date) updateTime.clone();
}
}
3.4 controller
package com.example.jpa_study.controller;
import com.example.jpa_study.controller.param.StudentParam;
import com.example.jpa_study.controller.vo.PageData;
import com.example.jpa_study.repository.entity.Student;
import com.example.jpa_study.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/student")
public class StudentController {
@Autowired
private StudentService studentService;
@PostMapping("/saveOrUpdate")
public boolean saveOrUpdate(@RequestBody Student stu) {
boolean result = false;
if (stu != null) {
result = studentService.saveOrUpdate(stu);
}
return result;
}
@PostMapping("/deleteStudentById")
public boolean deleteStudentById(@RequestBody List<String> ids) {
boolean result = studentService.deleteStudentById(ids);
return result;
}
@PostMapping("/list")
public PageData<Student> list(@RequestBody StudentParam params){
PageData<Student> students = studentService.list(params);
return students;
}
}
3.5 service以及impl
package com.example.jpa_study.service;
import com.example.jpa_study.controller.param.StudentParam;
import com.example.jpa_study.controller.vo.PageData;
import com.example.jpa_study.repository.entity.Student;
import java.util.List;
public interface StudentService {
/**
* 添加或修改学生信息
*
* @param stu
* @return
*/
boolean saveOrUpdate(Student stu);
/**
* 删除学生信息
*
* @param ids
* @return
*/
boolean deleteStudentById(List<String> ids);
/**
* 多条件模糊查询学生信息
*
* @param params
* @return
*/
PageData<Student> list(StudentParam params);
}
package com.example.jpa_study.service.impl;
import ch.qos.logback.core.util.TimeUtil;
import com.example.jpa_study.controller.param.StudentParam;
import com.example.jpa_study.controller.vo.PageData;
import com.example.jpa_study.repository.StudentRepository;
import com.example.jpa_study.repository.entity.Student;
import com.example.jpa_study.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
@Service
public class StudentServiceImpl implements StudentService {
@Autowired
private StudentRepository studentRepository;
@Override
public boolean saveOrUpdate(Student stu) {
Student student = studentRepository.save(stu);
return student != null;
}
@Override
public boolean deleteStudentById(List<String> ids) {
if (ids != null && ids.size() > 0) {
int num = 0;
for (String id : ids) {
studentRepository.deleteById(id);
num++;
}
return num == ids.size();
}
return false;
}
@Override
public PageData<Student> list(StudentParam content) {
int pageNo = 1;
int pageSize = 20;
if (content.getPageNo() != null && content.getPageSize() != null) {
pageNo = content.getPageNo();
pageSize = content.getPageSize();
}
PageData<Student> basePage = new PageData<>();
List<Sort.Order> orders = new ArrayList<>();
orders.add(new Sort.Order(Sort.Direction.DESC, "updateTime"));
Sort sort = Sort.by(orders);
Pageable pageable = PageRequest.of(pageNo - 1, pageSize, sort);
Page page = studentRepository.findAll((root, criteriaQuery, criteriaBuilder) -> {
List<Predicate> predicateList = new ArrayList<>();
if (content.getName() != null && content.getName() != "") {
String title=content.getName();
if(title.contains("_") || title.contains("%")){
//注:"\"被作为转义字符时必须也被转义
title = title.replace("\\","\\\\").replace("_","\\_").replace("%","\\%");
predicateList.add(criteriaBuilder.and(criteriaBuilder.like(root.get("name"), "%" + title + "%",'\\')));
}else{
predicateList.add(criteriaBuilder.and(criteriaBuilder.like(root.get("name"), "%" + content.getName() + "%")));
}
}
if (content.getAddress() != null && content.getAddress() != "") {
String title=content.getAddress();
if(title.contains("_") || title.contains("%")){
//注:"\"被作为转义字符时必须也被转义
title = title.replace("\\","\\\\").replace("_","\\_").replace("%","\\%");
predicateList.add(criteriaBuilder.and(criteriaBuilder.like(root.get("address"), "%" + title + "%",'\\')));
}else{
predicateList.add(criteriaBuilder.and(criteriaBuilder.like(root.get("address"), "%" + content.getAddress() + "%")));
}
}
return criteriaBuilder.and(
predicateList.toArray(new Predicate[predicateList.size()]));
}, pageable);
if (null != page && page.getSize() > 0) {
List<Student> result = page.getContent();
for (Student stu : result) {
Date birthDay = stu.getBirthDay();
Integer age=getStudentAge(birthDay);
stu.setAge(age);
}
basePage.setList(result);
basePage.setTotal(page.getTotalElements());
}
return basePage;
}
private Integer getStudentAge(Date birthDay) {
Calendar cal = Calendar.getInstance();
if (cal.before(birthDay)) {
//出生日期晚于当前时间,无法计算
throw new IllegalArgumentException(
"The birthDay is before Now.It's unbelievable!");
}
//当前年份
int yearNow = cal.get(Calendar.YEAR);
int monthNow = cal.get(Calendar.MONTH);
int dayOfMonthNow = cal.get(Calendar.DAY_OF_MONTH);
cal.setTime(birthDay);
int yearBirth = cal.get(Calendar.YEAR);
int monthBirth = cal.get(Calendar.MONTH);
int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);
//计算整岁数
int age = yearNow - yearBirth;
if (monthNow <= monthBirth) {
if (monthNow == monthBirth) {
//当前日期在生日之前,年龄减一
if (dayOfMonthNow < dayOfMonthBirth) {
age--;
}
} else {
//当前月份在生日之前,年龄减一
age--;
}
} return age;
}
}
3.6 Repository
package com.example.jpa_study.repository;
import com.example.jpa_study.repository.entity.Student;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface StudentRepository extends JpaRepository<Student,String> {
/**
* 多条件模糊查询
*
* @param spec
* @param pageable
* @return
*/
Page<Student> findAll(Specification<Student> spec, Pageable pageable);
}
3.7 启动类
package com.example.jpa_study;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class JpaStudyApplication {
public static void main(String[] args) {
SpringApplication.run(JpaStudyApplication.class, args);
}
}
3.8 JPA生成的数据库表结构
3.9 数据表中的现有数据
3.10 postman测试(添加和查询)