Spring Boot JPA
JPA
(Java Persistence API
)意即Java持久化API,主要包括三方面的技术
- ORM元数据
- API:操作实体对象进行CRUD操作
- 查询语言:通过面向对象的JPQL查询数据
JPA与Hibernate、Spring Data JPA
JPA是一种ORM规范,提供了一些API接口,并不是ORM实现。
Hibernate Jpa则是Hibernate对JPA的具体实现,是一套ORM框架
Spring Data Jpa在JPA规范下统一了各种ORM框架的Repository层的实现
JPA 使用
-
声明一个自定义的Repository接口继承JpaRepository<Class,type>接口,Class是对应的实体类型,type是实体类型的主键的类型
-
在接口中声明方法,JPA根据方法名解析进行查询,JPA本身已经声明了诸如findById()、findAll()、save()等基本方法,JPA的save()方法会检查实体是否存在主键,如果存在则为更新操作,不存在则为插入操作。
JPA接口方法命名规则
关键字 方法命名 sql where字句 And findByNameAndPwd where name= ? and pwd =? Or findByNameOrSex where name= ? or sex=? Is,Equals findById,findByIdEquals where id= ? Between findByIdBetween where id between ? and ? LessThan findByIdLessThan where id < ? LessThanEquals findByIdLessThanEquals where id <= ? GreaterThan findByIdGreaterThan where id > ? GreaterThanEquals findByIdGreaterThanEquals where id > = ? After findByIdAfter where id > ? Before findByIdBefore where id < ? IsNull findByNameIsNull where name is null isNotNull,NotNull findByNameNotNull where name is not null Like findByNameLike where name like ? NotLike findByNameNotLike where name not like ? StartingWith findByNameStartingWith where name like ‘?%’ EndingWith findByNameEndingWith where name like ‘%?’ Containing findByNameContaining where name like ‘%?%’ OrderBy findByIdOrderByXDesc where id=? order by x desc Not findByNameNot where name <> ? In findByIdIn(Collection<?> c) where id in (?) NotIn findByIdNotIn(Collection<?> c) where id not in (?) True findByAaaTue where aaa = true False findByAaaFalse where aaa = false IgnoreCase findByNameIgnoreCase where UPPER(name)=UPPER(?) -
注入自定义的Repository就可以使用方法查询
-
JPA支持自定义查询,在接口上面使用@Query注解加上JPQL语句即可,但是由于JPQL语法是以string类型写入,编译器无法发现错误,影响开发进度,因此尽量少使用JPQL。
JPA 实体建立
在JPA中维护one to one,one to many,many to one,many to many四种映射关系,在每个关系中,只有主表实体拥有连接列,从表实体不具有连接列,主表依赖于从表。
- 多对一
在多对一关系中,主表实体为“多”的一方,拥有连接列,注解@JoinColumn用于指定连接列(外键列),注解属性name用于指明数据库列名,加在从表实体类型("一"的一方的类型)的属性上,一般与@ManyToOne一起使用,@ManyToOne标注在代表One的实体类型的属性上,@OneToMany注解标注在代表Many的实体类型的属性上,此属性属于“一”的一方,也就是从表实体,不拥有连接列,可以再使用mappedBy属性指明主表实体的连接属性名称,因此mappedBy和@JoinColumn不能同时使用,@OneToMany加在从表实体中list类型主表实体的属性上。在one to many或者many to one关系持久化时,总是先持久化"一"的一方,再持久化"多"的一方。示例Student和Grade是多对一关系。JPA的@Id位于javax.persistence.Id
/*
* Student类
*/
@Entity
@Table(name="student")
public class Student{
@Id
@Column(name="student_id")
private String id;
@Column
private String name;
@JoinColumn(name="grade_id")
@ManyToOne
private Grade grade;
//getter and setter
}
/*
* Grade类
*/
@Entity
@Table(name="grade")
public class Grade{
@Id
@Column(name="grade_id")
private Integer id;
@Column(name="grade_name")
private String gradeName;
@OneToMany(mappedBy="grade")
private List<Student> studentList;
//getter and setter
}
- 多对多
必须指定多对多关系中的一方为主表实体,另一方为从表实体,在主表实体中使用@JoinTable的name属性指明多对多关系的连接表,joinColumns用于指定连接表中主表连接的列名,inverseJoinColumns用于指定连接表中从表连接的列名,主表中@JoinTable与@ManyToMany一般同时注解在对方实体List类型的属性上。示例Employee和Projuct是多对一关系。
/*
* Employee类
*/
@Entity
@Table("name="employee")
public class Employee{
@Id
@Column(name="id")
private String id;
@Column(name="name")
private String employee_name;
@JoinTable(name="employee_project_inner",
joinColumns={@JoinColumn(name="employee_id",referencedColumnName="id")},
inverseJoinColumns={@JoinColumn(name="project_id",referencedColumnName="id")})
@ManyToMany
private List<ProjectInfo> projects;
//getter and setter
}
/*
* Project类
*/
@Entity
@Table(name="project")
public class Project{
@Id
@Column(name="id")
private Integer id;
@Column(name="name")
private String project_name;
@ManyToMany(mappedBy="projects")
private List<Employee> employees;
//getter and setter
}
- 一对一
/*
* Customer类
*/
@Entity
@Table(name="customer")
public class Customer{
@Id
@Column(name="id")
private String id;
@Column(name="name")
private String name;
@JoinColumn(name="ps_id")
@OneToOne
private ParkingSpace parkingSpace;
//getter and setter
}
/*
* ParkingSpace类
*/
@Entity
@Table(name="parking_space")
public class ParkingSpace{
@Id
@Column(name="id")
private String id;
@Column(name="location")
private String location;
@OneToOne(mappedBy="parkingSpace")
private Employee employee;
}
- 注1:on update cascade级联更新:主键表更新了id,外键表的外键随之更新;on delete cascade级联删除:主键表删除某id行,外键表删除对应外键行,建立的实体应该与数据库设计一致,至少无冲突,互补也是可以的,详细的实体设计大概是为了从代码生成数据库表,如果更喜欢使用SQL语句创建数据表的话,类似索引的信息可以不用在实体类上标注
- 注2:使用了JPA这种实体间的关联后,每次查询主表实体或者从表实体都能查询到对应的对方的实体信息,非常简便
- 注3:相关MySQL表
/*一对一*/
CREATE TABLE parking_space(
id VARCHAR(32) NOT NULL,
location VARCHAR(50) NOT NULL COMMENT '停车位置',
PRIMARY KEY (id)
) COMMENT '停车位表'
CREATE TABLE customer(
id VARCHAR(32) NOT NULL,
name VARCHAR(50) NOT NULL COMMENT '顾客名字',
ps_id VARCHAR(32) NOT NULL COMMENT '停车位id,外键',
PRIMARY KEY (id),
FOREIGN KEY (ps_id) REFERENCES parking_space (id) ON DELETE CASCADE ON UPDATE CASCADE
) COMMENT '顾客表'
/*多对多*/
CREATE TABLE employee(
id VARCHAR(32) NOT NULL,
employee_name VARCHAR(50) NOT NULL COMMENT '名字',
PRIMARY KEY (id)
) COMMENT '雇员表'
CREATE TABLE project(
id VARCHAR(32) NOT NULL,
project_name VARCHAR(50) NOT NULL COMMENT '项目名称',
PRIMARY KEY (id)
) COMMENT '项目表'
DROP TABLE employee_project_inner
CREATE TABLE employee_project_inner(
employee_id VARCHAR(32) NOT NULL COMMENT '雇员id',
project_id VARCHAR(32) NOT NULL COMMENT '项目id',
PRIMARY KEY (employee_id,project_id),#联合主键
FOREIGN KEY (employee_id) REFERENCES employee (id) ON UPDATE CASCADE ON DELETE CASCADE,#外键
FOREIGN KEY (project_id) REFERENCES project (id) ON UPDATE CASCADE ON DELETE CASCADE,#外键
UNIQUE KEY uqe_emp_pjt (employee_id,project_id) #复合唯一索引
) COMMENT '雇员项目关系表'