详解 Spring Data JPA


3个月前 187次点击 来自 后端

标签: JPA

原文地址:详解 spring data jpa ,全方位总结,干货分享

自定义查询

使用关键字


使用 sql 增删改查

  • JPQL 形式的 sql 语句,from 后面是以类名呈现的。
  • 原生的 sql 语句,需要使用 nativeQuery = true 指定使用原生 sql

sql 中的参数传递也有两种形式:

  • 使用问号 ?,紧跟数字序列,数字序列从1 开始,如 ?1 接收第一个方法参数的值。
  • 使用冒号:,紧跟参数名,参数名是通过@Param 注解来确定。
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);
}

Sort 排序

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

测试

public List<Teacher> getTeachers(@PathVariable("subject") String subject) {
    // 1. 第一种方法实例化出 Sort 类,根据年龄进行升序排列
    Sort sort1 = Sort.by(Sort.Direction.ASC, "age");

    // 2. 定义多个字段的排序
    Sort sort2 = Sort.by(Sort.Direction.DESC, "id", "age");

    // 3. 通过实例化 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);
}

Pageable 是一个接口类,它的实现类是 PageRequest

public Page<Teacher> getPage(@PathVariable("subject") String subject) {
    // 1. 第一种方法实例化 Pageable
    Pageable pageable1 = PageRequest.of(1, 2);

    // 2. 第二种实例化 Pageable
    Sort sort = Sort.by(Sort.Direction.ASC, "age");
    Pageable pageable2 = PageRequest.of(1, 2, sort);

    // 3. 第三种实例化 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;
}

Specification

接口继承 JpaSpecificationExecutor

public interface TeacherRepositoty extends JpaRepository<Teacher,Integer> , JpaSpecificationExecutor {
}

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

}

Specification 是一个函数式接口,里面有一个抽象的方法:

Predicate toPredicate(Root<T> var1, CriteriaQuery<?> var2, CriteriaBuilder var3);

实现该方法我们不需要弄清楚 Predicate , Root , CriteriaQuery 和 CriteriaBuilder 四个类的使用规则:

现在有这样的一条 sql 语句 : select * from teacher where age > 20

  • Predicate 是用来建立 where 后的查寻条件的相当于上述sql语句的 age > 20。
  • Root 使用来定位具体的查询字段,比如 root.get(“age”) ,定位 age字段,
  • CriteriaBuilder是用来构建一个字段的范围,相当于 > ,= ,<,and …. 等等
  • CriteriaQuery 可以用来构建整个 sql 语句,可以指定sql 语句中的 select 后的查询字段,也可以拼接 where , groupby 和 having 等复杂语句。

案例:

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

Projection

现在的需求是我只需要 Teacher 类对应的表 teacher 中的 name 和 age 的数据,其他数据不需要。 定义一个如下的接口:

public interface TeacherProjection {

    String getName();

    Integer getAge();

    @Value("#{target.name +' and age is' + target.age}")
    String getTotal();
}

接口中的方法以 get 开头 + 属性名,属性名首字母大写, 例如 getName(), 也可以通过 @Value 注解中使用 target.属性名获取属性,也可以把多个属性值拼接成一个字符串。

public interface TeacherRepositoty extends JpaRepository<Teacher,Integer>, JpaSpecificationExecutor {

   // 返回 TeacherProjection 接口类型的数据
    @Query("select t from Teacher t ")
    List<TeacherProjection> getTeacherNameAndAge();
}

测试

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

查看结果我们会发现,我们仅仅只是拿到 name 和 age 的字段值而已。

Made with in Shangrao,China By Devler.

Copyright © Devler 2012 - 2022

赣ICP备19009883号-1

Top ↑