SpringBoot中使用JPA进行一对多查询

一、JPA介绍

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 都可以依赖于它来实现

二、项目搭建

2.1添加Spring Data JPA依赖



    org.springframework.boot
    spring-boot-starter-data-jpa
    2.5.0

2.2 添加数据库驱动依赖



    mysql
    mysql-connector-java
    8.0.25

2.3添加配置文件 application.yml

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

三、编写代码

3.1编写实体类

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 + ''' +
                '}';
    }
}

3.2 编写Repository接口

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);
    }
 }

最后可以看到查询情况如下:
SpringBoot中使用JPA进行一对多查询_第1张图片
SpringBoot中使用JPA进行一对多查询_第2张图片
以上就是JPA的简单一对多使用和介绍。

你可能感兴趣的:(java)