Jpa (Java Persistence API) 是 Sun 官方提出的 Java 持久化规范。它为 Java 开发人员提供了一种对象/关联映射工具来管理 Java 应用中的关系数据。它的出现主要是为了简化现有的持久化开发工作和整合 ORM 技术,结束现在 Hibernate,TopLink,JDO 等 ORM 框架各自为营的局面。
值得注意的是,Jpa是在充分吸收了现有 Hibernate,TopLink,JDO 等 ORM 框架的基础上发展而来的,具有易于使用,伸缩性强等优点。从目前的开发社区的反应上看,Jpa 受到了极大的支持和赞扬,其中就包括了 Spring 与 EJB3. 0的开发团队。
注意:Jpa 是一套规范,不是一套产品,那么像 Hibernate,TopLink,JDO 他们是一套产品,如果说这些产品实现了这个 Jpa 规范,那么我们就可以叫他们为 Jpa 的实现产品。
Spring Boot Jpa 是 Spring 基于 ORM 框架、Jpa 规范的基础上封装的一套 Jpa 应用框架,可使开发者用极简的代码即可实现对数据的访问和操作。它提供了包括增删改查等在内的常用功能,且易于扩展!学习并使用 Spring Data Jpa 可以极大提高开发效率!
Spring Boot Jpa 让我们解脱了 DAO 层的操作,基本上所有 CRUD 都可以依赖于它来实现
org.springframework.boot
spring-boot-starter-data-jpa
2.5.0
mysql
mysql-connector-java
8.0.25
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username: root
password: 123456
tomcat:
max-active: 20
max-idle: 8
initial-size: 10
jpa:
hibernate:
ddl-auto: update
show-sql: true
database: mysql
open-in-view: true #解决no-Session的问题
properties:
hibernate:
enable_lazy_load_no_trans: true
JPA中实体类注解介绍:@Entity为指定改类为表实体类,name属性对应为数据库表名,@Id为指定该字段为数据库主键,@GeneratedValue为指定主键的增长策略,@GenericGenerator为自定义主键的增长策略,当我们需要一对多操作时只需要在该实体类引用需要操作的实体类,并加上@OneToMany(mappedBy = “department”, cascade = {CascadeType.ALL}, fetch = FetchType.LAZY)注解,其中@OneToMany表名是一对多操作,mappedBy是映射的实体类名,cascade 为级联,当我们对该字段操作变化时,依赖他的字段都会随着发生变化,fetch 为加载时机(LAZY为懒加载,EAGER为及时加载)。
3.1.1 部门表(Department)
package com.ls.entity;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;
import java.util.Set;
/*
* @Author:Alan
* @Date:2021/6/8 16:53
* @Description 部门实体类
* @param: null
* @return
*/
@Entity(name = "tb_dept")
//@Data
@Getter
@Setter
public class Department {
@Id
@GenericGenerator(name = "idGenerator", strategy = "uuid")
@GeneratedValue(generator = "idGenerator")
private String id;
private String deptName;
//希望:查询一个部门的所有信息的信息,同时查询数这个部门中所有员工的所有信息。
/*
cascade:级联(一个犯法,满门cz)
CascadeType.MERGE级联更新:若User属性修改了那么中间表保存时同时修改items里的对象。对应EntityManager的merge方法 (较常用 )
CascadeType.PERSIST级联保存:对user对象保存时也对role里的对象也会保存。对应EntityManager的presist方法
CascadeType.REFRESH级联刷新:获取user对象也同时也重新获取最新的role时的对象。对应EntityManager的refresh(object)方法有效。即会重新查询数据库里的最新数据
CascadeType.REMOVE级联删除:对users对象删除也对中间表role里的对象也会删除。对应EntityManager的remove方法
CascadeType.ALL包含所有;
fetch:抓取策略
fetch.lazy :懒加载 获取Department对象信息时,不会马上去获取该部门对应的所有员工信息
当我们通过department.getEmployees*()是才会去获取该用户的所有角色的所有信息。
fetch.EAGER 立即加载 获取user对象信息时,会立即获取该用户所对用的所有角色的所有信息。
mappedBy:必须与员工的Department的属性名一致,否则查询不出员工信息
*/
//jpa could not initialize proxy - no Session
@OneToMany(mappedBy = "department", cascade = {CascadeType.ALL}, fetch = FetchType.LAZY)
//@OneToMany(mappedBy = "department",cascade = {CascadeType.ALL},fetch = FetchType.EAGER)
private Set employees;
@Override
public String toString() {
return "Department{" +
"id='" + id + ''' +
", deptName='" + deptName + ''' +
'}';
}
3.1.2 员工表(Employee)
每个员工只属于一个部门,而一个部门可以有多个员工,所有在员工表中定义部门实体类时需要加上 @ManyToOne(targetEntity = Department.class,fetch = FetchType.EAGER),ManyToOne为多对一注解,targetEntity 为目标的实体类名,fetch 为加载时机, @JoinColumn(name=“dept_id”,referencedColumnName = “id”),JoinColumn的name属性为目标连接的字段名,referencedColumnName 为自己所引用的字段名。
package com.ls.entity;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;
/**
* @ClassName Employee
* @Description 员工实体类
* @Author Alan
* @Date 2021/6/8 16:53
* @Version 1.0
**/
@Entity
@Table(name="tb_emp")
//@Data
@Getter
@Setter
public class Employee {
@Id
//主键字符串,通过程序自动生产主键值
@GenericGenerator(name = "idGenerator", strategy = "uuid")
@GeneratedValue(generator = "idGenerator")
private String id;
private String empName;
private String empJob;
//只查找部门的id
//private String deptId;
//希望:查询这个员工所有的信息的时候,同时也查出这个员工的部门的所有信息
/*cascade:级联(一个犯法,满门cz)
CascadeType.MERGE级联更新:若User属性修改了那么中间表保存时同时修改items里的对象。对应EntityManager的merge方法 (较常用 )
CascadeType.PERSIST级联保存:对user对象保存时也对role里的对象也会保存。对应EntityManager的presist方法
CascadeType.REFRESH级联刷新:获取user对象也同时也重新获取最新的role时的对象。对应EntityManager的refresh(object)方法有效。即会重新查询数据库里的最新数据
CascadeType.REMOVE级联删除:对users对象删除也对中间表role里的对象也会删除。对应EntityManager的remove方法
CascadeType.ALL包含所有;
fetch:抓取策略
fetch.lazy :懒加载 获取user对象信息时,不会马上去获取该用户对应的所有角色信息
当我们通过user.getRoles是才会去获取该用户的所有角色的所有信息。
fetch.EAGER 立即加载 获取user对象信息时,会立即获取该用户所对用的所有角色的所有信息。
*/
@ManyToOne(targetEntity = Department.class,fetch = FetchType.EAGER)
@JoinColumn(name="dept_id",referencedColumnName = "id")
private Department department;
@Override
public String toString() {
return "Employee{" +
"id='" + id + ''' +
", empName='" + empName + ''' +
", empJob='" + empJob + ''' +
'}';
}
}
Repository接口类似MybBatis的mapper接口,它通过实现JpaRepository<实体类,主键类型>,它内部实现了基本的增(save)删(deleteById)查(findAll)改(save(需要修改的id))方法。
3.2.1 部门接口(DepartmentRepository)
package com.ls.repository;
import com.ls.entity.Department;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
/*
* @Author:Alan
* @Date:2021/6/8 23:08
* @Description 部门接口
* @param: null
* @return
*/
@Repository
public interface DepartmentRepository extends JpaRepository {
// 通过部门名称查询
Department findByDeptName(String deptName);
}
3.2.2 员工接口(EmployeeRepository)
package com.ls.repository;
import com.ls.entity.Employee;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
/*
* @Author:Alan
* @Date:2021/6/8 16:54
* @Description 员工接口
* @param: null
* @return
*/
@Repository
public interface EmployeeRepository extends JpaRepository {
}
// 查询部门表下有多少员工
@SpringBootTest
public class UserRoleTest {
@Autowired
private DepartmentRepository departmentRepository;
@Autowired
private EmployeeRepository employeeRepository;
@Autowired
@Test
void Test01() {
Department department = departmentRepository.findByDeptName("开发部");
System.out.println(department);
Set employeeSet = department.getEmployees();
employeeSet.forEach(System.out::println);
}
}