背景
项目中我们经常用到分页查询,一般使用的场景有两个
-
前端查询大批量数据时指定page、size分页查询
-
后台定时处理一批数据时,从数据库获取待处理数据,从而避免一次查询太多数据到内存,处理完一批后再查询下一页的数据处理
对于场景2也有两种实现方式,Page和Slice,下面就分别介绍
Page
public interface UserRepository extends JpaRepository<User,Long> {
Page<User> findByAge(int age, Pageable pageable);
}
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class JpaTests {
@Autowired
private UserRepository userRepository;
@Before
public void before(){
userRepository.saveAll(Arrays.asList(
new User(null,"刘","一", 20),
new User(null,"陈","二", 20),
new User(null,"张","三", 20),
new User(null,"李","四", 20),
new User(null,"王","五", 20),
new User(null,"赵","六", 20),
new User(null,"孙","七", 20),
new User(null,"周","八", 20)
));
}
@Test
public void queryByPage(){
int pageNum = 0;
while(true){
Pageable pageable = PageRequest.of(pageNum, 3);
Page<User> page = userRepository.findByAge(20, pageable);
List<User> users = page.getContent();
users.forEach(System.out::println);
if (users.size() == 0){
break;
}
pageNum++;
}
}
}
控制台输出
Hibernate: select user0_.id as id1_0_, user0_.age as age2_0_, user0_.first_name as first_na3_0_, user0_.last_name as last_nam4_0_ from t_user user0_ where user0_.age=? limit ?
Hibernate: select count(user0_.id) as col_0_0_ from t_user user0_ where user0_.age=?
User(id=1, firstName=刘, lastName=一, age=20)
User(id=2, firstName=陈, lastName=二, age=20)
User(id=3, firstName=张, lastName=三, age=20)
Hibernate: select user0_.id as id1_0_, user0_.age as age2_0_, user0_.first_name as first_na3_0_, user0_.last_name as last_nam4_0_ from t_user user0_ where user0_.age=? limit ? offset ?
Hibernate: select count(user0_.id) as col_0_0_ from t_user user0_ where user0_.age=?
User(id=4, firstName=李, lastName=四, age=20)
User(id=5, firstName=王, lastName=五, age=20)
User(id=6, firstName=赵, lastName=六, age=20)
Hibernate: select user0_.id as id1_0_, user0_.age as age2_0_, user0_.first_name as first_na3_0_, user0_.last_name as last_nam4_0_ from t_user user0_ where user0_.age=? limit ? offset ?
User(id=7, firstName=孙, lastName=七, age=20)
User(id=8, firstName=周, lastName=八, age=20)
代码比较简单,就是循环增加pageNum,只到查询为空就终止
Slice
Slice是一个数据块,表明是否有更多可用数据,能够循环的获取数据。
@Test
public void queryBySlice(){
Pageable pageable = PageRequest.of(0,3);
while(true){
Slice<User> slice = userRepository.findByAge(20, pageable);
List<User> users = slice.getContent();
users.forEach(System.out::println);
if (!slice.hasNext()){
break;
}
pageable = slice.nextPageable();
}
}
可以看到跟Page的区别是,不需要自定义的判断是否有数据,也不用自己累加页数了。使用slice.hasNext()就能判断是否还有下一个Slice,这里要注意需要调用slice.nextPageable()获取下一个pageable,怎么样看起来是不是比Page更高级。