查询方法
- 类层次关系图
- 查询策略
- queryLookupStrategy
- 创建查询方法
- 关键字列表
- PartTree.class
- 使用Projections扩展查询结果
- 使用投影返回部分字段
- 1.声明一个接口
- 2.查询关联的子对象
- 3. 支持@Value和SPEL
- 综合前面第1.和第2.我进行以下实验
- 1. 在实体类增加几个方法
- 2. 在接口里增加相应方法
- 3. 执行结果
- 4. 结论
- 原生SQL查询 分页
- ExampleMatcher
类层次关系图
查询策略
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,中间补充实体类里的字段即可。
关键字列表
PartTree.class
从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();
…
}
- 此处 target 指的是与这个接口有关的实体类,firstname是实体类里的属性,不存在会报错;
- Projection接口中必须以“getXXX”来命名方法,关于“XXX”则是要与查询语句中的别名相对应,否则用@Value{"${target.xxx}"}注解来调整,注意其中的target不能省略,可以把target看成用别名查出来的临时对象,这样就好理解了。
综合前面第1.和第2.我进行以下实验
1. 在实体类增加几个方法
2. 在接口里增加相应方法
3. 执行结果
[
{
"name": "张三",
"all": "张三1",
"age": 18,
"a": "张三18"
}
]
4. 结论
- 可以看到2中的方法可以是实体类中存在的任意方法,前提是这个方法不能有参数,可以看到2中图里没有参数的方法前面会有对应的一个spring标志,有参数就没有。
- 返回结果中也是,只有无参方法生成了相应的字段,并且返回结果中所有字段名是 方法名去掉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