centos 7.2 做网站,做.net网站流程,文山专业网站建设报价,微网站 合同参数选择#xff08;Sort/Pageable#xff09;分页和排序 特定类型的参数#xff0c;Pageable 并动态 Sort 地将分页和排序应用于查询
案例#xff1a;在查询方法中使用 Pageable、Slice 和 Sort。
PageUser findByLastname(String lastname, Pageable pageable)…参数选择Sort/Pageable分页和排序 特定类型的参数Pageable 并动态 Sort 地将分页和排序应用于查询
案例在查询方法中使用 Pageable、Slice 和 Sort。
PageUser findByLastname(String lastname, Pageable pageable);
SliceUser findByLastname(String lastname, Pageable pageable);
ListUser findByLastname(String lastname, Sort sort);
ListUser findByLastname(String lastname, Pageable pageable);
第一种方法允许将 org.springframework.data.domain.Pageable 实例传递给查询方法以动态地将分页添加到静态定义的查询中Page 知道可用的元素和页面的总数它通过基础框架里面触发计数查询来计算总数。由于这可能是昂贵的这取决于所使用的场景说白了当用到 Pageable 的时候会默认执行一条 cout 语句。而 Slice 的用作是只知道是否有下一个 Slice 可用不会执行count所以当查询较大的结果集时只知道数据是足够的而相关的业务场景也不用关心一共有多少页。
排序选项也通过 Pageable 实例处理如果只需要排序需在 org.springframework.data.domain.Sort 参数中添加一个参数即可正如看到的只需返回一个 List 也是可能的。在这种情况下Page 将不会创建构建实际实例所需的附加元数据这反过来意味着必须不被发布的附加计数查询而仅仅是限制查询仅查找给定范围的实体。
限制查询结果
案例在查询方法上加限制查询结果的关键字 First 和 top。
User findFirstByOrderByLastnameAsc();
User findTopByOrderByAgeDesc();
PageUser queryFirst10ByLastname(String lastname, Pageable pageable);
SliceUser findTop3ByLastname(String lastname, Pageable pageable);
ListUser findFirst10ByLastname(String lastname, Sort sort);
ListUser findTop10ByLastname(String lastname, Pageable pageable);
查询方法的结果可以通过关键字来限制 first 或 top其可以被可互换使用可选的数值可以追加到顶部/第一个以指定要返回的最大结果的大小。如果数字被省略则假设结果大小为 1限制表达式也支持 Distinct 关键字。此外对于将结果集限制为一个实例的查询支持将结果包装到一个实例中 Optional。如果将分页或切片应用于限制查询分页以及可用页数的计算则在限制结果中应用。
查询结果的不同形式List/Stream/Page/Future
Page 和 List 在上面的案例中都有涉及下面将介绍的几种特殊的方式。
流式查询结果
可以通过使用 Java 8 StreamT 作为返回类型来逐步处理查询方法的结果而不是简单地将查询结果包装在 Stream 数据存储中特定的方法用于执行流。
示例使用 Java 8 流式传输查询的结果 StreamT。
Query(select u from User u)
StreamUser findAllByCustomQueryAndStream();
StreamUser readAllByFirstnameNotNull();
Query(select u from User u)
StreamUser streamAllPaged(Pageable pageable);
注意流的关闭问题try catch 是一种用关闭方法。
StreamUser stream;
try {stream repository.findAllByCustomQueryAndStream()stream.forEach(…);
} catch (Exception e) {e.printStackTrace();
} finally {if (stream!null){stream.close();}
}
异步查询结果
可以使用 Spring 的异步方法执行功能异步执行存储库查询这意味着方法将在调用时立即返回并且实际的查询执行将发生在已提交给 Spring TaskExecutor 的任务中比较适合定时任务的实际场景。
Async
FutureUser findByFirstname(String firstname); (1)
Async
CompletableFutureUser findOneByFirstname(String firstname); (2)
Async
ListenableFutureUser findOneByLastname(String lastname);(3)
使用 java.util.concurrent.Future 的返回类型。使用 java.util.concurrent.CompletableFuture 作为返回类型。使用 org.springframework.util.concurrent.ListenableFuture 作为返回类型。
所支持的返回结果类型远不止这些可以根据实际的使用场景灵活选择其中 Map 和 Object[] 的返回结果也支持这种方法不太推荐使用应为没有用到对象思维不知道结果里面装的是什么。
下表列出了 Spring Data JPA Query Method 机制支持的方法的返回值类型。
某些特定的存储可能不支持全部的返回类型。 只有支持地理空间查询的数据存储才支持 GeoResult、GeoResults、GeoPage 等返回类型。
而我们要看引用的那个 Spring Data 的实现子模块以 Spring Data JPA 为例看看 JPA 默认帮实现了哪些返回值类型。 还是通过工具分析 JpaRepository 帮我们实现了哪些返回类型这样不至于直接看官方文档的时候一头雾水。 Projections 对查询结果的扩展
Spring JPA 对 Projections 的扩展的支持个人觉得这是个非常好的东西从字面意思上理解就是映射指的是和 DB 的查询结果的字段映射关系。一般情况下我们是返回的字段和 DB 的查询结果的字段是一一对应的但有的时候需要返回一些指定的字段不需要全部返回或者返回一些复合型的字段还得自己写逻辑。Spring Data 正是考虑到了这一点允许对专用返回类型进行建模以便更有选择地将部分视图对象。
假设 Person 是一个正常的实体和数据表 Person 一一对应我们正常的写法如下
Entity
class Person {IdUUID id;String firstname, lastname;Address address;Entitystatic class Address {String zipCode, city, street;}
}
interface PersonRepository extends RepositoryPerson, UUID {CollectionPerson findByLastname(String lastname);
}
1但是我们想仅仅返回其中的 name 相关的字段应该怎么做呢如果基于 projections 的思路其实是比较容易的。只需要声明一个接口包含我们要返回的属性的方法即可。如下
interface NamesOnly {String getFirstname();String getLastname();
}
Repository 里面的写法如下直接用这个对象接收结果即可如下
interface PersonRepository extends RepositoryPerson, UUID {CollectionNamesOnly findByLastname(String lastname);
}
Ctroller 里面直接调用这个对象可以看看结果。
原理是底层会有动态代理机制为这个接口生产一个实现实体类在运行时。 2查询关联的子对象一样的道理如下
interface PersonSummary {String getFirstname();String getLastname();AddressSummary getAddress();interface AddressSummary {String getCity();}
}
3Value 和 SPEL 也支持
interface NamesOnly {Value(#{target.firstname target.lastname})String getFullName();…
}
PersonRepository 里面保持不变这样会返回一个 firstname 和 lastname 相加的只有 fullName 的结果集合。
4对 Spel 表达式的支持远不止这些
Component
class MyBean {String getFullName(Person person) {…//自定义的运算}
}
interface NamesOnly {Value(#{myBean.getFullName(target)})String getFullName();…
}
5还可以通过 Spel 表达式取到方法里面的参数的值。
interface NamesOnly {Value(#{args[0] target.firstname !})String getSalutation(String prefix);
}
6这时候有人会在想只能用 interface 吗dto 支持吗也是可以的也可以定义自己的 Dto 实体类需要哪些字段我们直接在 Dto 类当中暴漏出来 get/set 属性即可如下
class NamesOnlyDto {private final String firstname, lastname;
//注意构造方法NamesOnlyDto(String firstname, String lastname) {this.firstname firstname;this.lastname lastname;}String getFirstname() {return this.firstname;}String getLastname() {return this.lastname;}
}
7支持动态 Projections想通过泛化根据不同的业务情况返回不通的字段集合。
PersonRepository做一定的变化如下
interface PersonRepository extends RepositoryPerson, UUID {CollectionT findByLastname(String lastname, ClassT type);
}
我们的调用方就可以通过 class 类型动态指定返回不同字段的结果集合了如下
void someMethod(PersonRepository people) {
//我想包含全字段就直接用原始entityPerson.class接收即可CollectionPerson aggregates people.findByLastname(Matthews, Person.class);
//如果我想仅仅返回名称我只需要指定Dto即可。CollectionNamesOnlyDto aggregates people.findByLastname(Matthews, NamesOnlyDto.class);
}
最后Projections 的应用场景还是挺多的望大家好好体会这样可以实现更优雅的代码去实现不同的场景。不必要用数组冗余的对象去接收查询结果。