查询方法

  • 类层次关系图
  • 查询策略
  • queryLookupStrategy
  • 创建查询方法
  • 关键字列表
  • PartTree.class
  • 使用Projections扩展查询结果
  • 使用投影返回部分字段
  • 1.声明一个接口
  • 2.查询关联的子对象
  • 3. 支持@Value和SPEL
  • 综合前面第1.和第2.我进行以下实验
  • 1. 在实体类增加几个方法
  • 2. 在接口里增加相应方法
  • 3. 执行结果
  • 4. 结论
  • 原生SQL查询 分页
  • ExampleMatcher


类层次关系图

java jpa 范围查询 jpa查询数据_java jpa 范围查询

查询策略

queryLookupStrategy

  • @EnableJpaRepositories(queryLookupStrategy= QueryLookupStrategy.Key.CREATE_IF_NOT_FOUND)可以配置方法的查 询策略,其中QueryLookupStrategy.Key的值一共有三个:
  • CREATE:直接根据方法名进行创建。如果方法名不符合规则,启动 的时候就会报异常。
  • USE_DECLARED_QUERY:尝试查找已声明的查询,如果找不到则抛出异常。
  • CREATE_IF_NOT_FOUND:这个是默认的,以上两种方式的结合 版。先用声明方式进行查找,如果没有找到与方法相匹配的查 询,就用create的方法名创建规则创建一个查询。

创建查询方法

Spring Data 存储库基础结构中内置了查询构建器机制,对于在存储库实体上构建约束查询很有用,方法的前缀有find…By、 read…By、query…By、count…By和get…By,中间补充实体类里的字段即可。

关键字列表

java jpa 范围查询 jpa查询数据_spring boot_02


java jpa 范围查询 jpa查询数据_spring boot_03

PartTree.class

java jpa 范围查询 jpa查询数据_jpa_04

从PatrTree类里看到查询前缀除了find还有很多种

private static final String QUERY_PATTERN = "find|read|get|query|search|stream";
private static final String COUNT_PATTERN = "count";
private static final String EXISTS_PATTERN = "exists";
private static final String DELETE_PATTERN = "delete|remove";

使用Projections扩展查询结果

Spring JPA对Projections扩展的支持是非常好的。从字面意思 上理解就是映射,指的是和DB查询结果的字段映射关系。一般情况
下,返回的字段和DB查询结果的字段是一一对应的,但有的时候,我 们需要返回一些指定的字段,不需要全部返回,或者只返回一些复合
型的字段,还要自己写逻辑。Spring Data正是考虑到了这一点,允 许对专用返回类型进行建模,以便我们有更多的选择,将部分字段显
示成视图对象

@Table(name = "view_dbc")
@Entity
@Data
public class ViewDbcEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", nullable = false)
    private Long id;

    @Column(name = "name", nullable = false)
    private String name;

    @Column(name = "age")
    private Integer age;


}

需求:我想只返回姓名和年龄

使用投影返回部分字段

1.声明一个接口

声明一个接口,在接口里面包含要返回的属性的方法,比如

public interface NameAndAge {
    String getName();
    Integer getAge();

}

Repository里面的写法如下,直接用这个对象接收结果即可:

public interface ViewDbcRepository extends JpaRepository<ViewDbcEntity,Long>, JpaSpecificationExecutor<ViewDbcEntity> {

    Collection<NameAndAge> findAllById(Long id);
}

在Ctroller里面直接调用对象可以查看结果。原理是运行时底层 会有动态代理机制为这个接口生成一个实现实体类。查询执行引擎在运行时为返回的每个元素创建该接口的代理实例,并将对公开方法的调用转发给目标对象

2.查询关联的子对象

投影可以递归使用

interface PersonSummary {

  String getFirstname();
  String getLastname();
  AddressSummary getAddress();

  interface AddressSummary {
    String getCity();
  }
}

在方法调用时,将获得目标实例的address属性,并将其包装到投影代理中

3. 支持@Value和SPEL

interface NamesOnly {

  @Value("#{target.firstname + ' ' + target.lastname}")
  String getFullName();
  …
}
  1. 此处 target 指的是与这个接口有关的实体类,firstname是实体类里的属性,不存在会报错;
  2. Projection接口中必须以“getXXX”来命名方法,关于“XXX”则是要与查询语句中的别名相对应,否则用@Value{"${target.xxx}"}注解来调整,注意其中的target不能省略,可以把target看成用别名查出来的临时对象,这样就好理解了。

综合前面第1.和第2.我进行以下实验

1. 在实体类增加几个方法

java jpa 范围查询 jpa查询数据_jpa_05

2. 在接口里增加相应方法

java jpa 范围查询 jpa查询数据_spring boot_06

3. 执行结果
[
  {
    "name": "张三",
    "all": "张三1",
    "age": 18,
    "a": "张三18"
  }
]
4. 结论
  1. 可以看到2中的方法可以是实体类中存在的任意方法,前提是这个方法不能有参数,可以看到2中图里没有参数的方法前面会有对应的一个spring标志,有参数就没有。
  2. 返回结果中也是,只有无参方法生成了相应的字段,并且返回结果中所有字段名方法名去掉get以后得到的字符串且首字母转化为小写,其实就是直接使用entity类里@Getter方法就可以了

原生SQL查询 分页

public interface AreaInfoRepository extends JpaRepository<AreaInfoEntity,String>, JpaSpecificationExecutor<AreaInfoEntity> {


    List<AreaInfoEntity> findAllByIdContaining(String id);

    @Query(nativeQuery = true,
            value = "select * from spring.area_info where id REGEXP ?1 /* #pageable# */",
            countQuery = "select COUNT(*) from spring.area_info where id REGEXP ?1")
    Page<AreaInfoEntity> findAllByIdTest(String id, Pageable pageable);


}
Hibernate: 
    select
        * 
    from
        spring.area_info 
    where
        id REGEXP ? /* #pageable# */ 
    order by
        ordernum desc
Hibernate: 
    select
        COUNT(*) 
    from
        spring.area_info 
    where
        id REGEXP ?
total27
14
0
2
27
ordernum: DESC

返回结果里content返回了所有记录,并不是只返回了本页记录
getNumberOfElements()函数返回了总有记录数

ExampleMatcher