1. 概述
Spring Data Repositories 提供了灵活的方式,在List
或Stream
中查询大量数据。在这篇教程中,我们将学习如何在List
和Stream
中查询数据,并了解何时使用它们。
2. List
与Stream
我们知道,社交媒体网站拥有数百万用户的详细信息。假设我们需要找到所有年龄大于20岁的用户。本节将通过返回List
和Stream
的查询来解决这个问题,并理解这两种查询方式的工作原理。
由于我们将使用代码示例,运行这些示例需要一些前提条件。我们使用的是H2数据库。User
是我们的实体,具有firstName
、lastName
和age
等属性。我们在测试类的setup方法中持久化了一些用户。我们使用了Java Faker库为这个实体生成随机数据。
2.1. List
在Java中,List
是一个接口,有多种实现,如ArrayList
、LinkedList
等,用于存储一组数据。
以下示例中,我们将编写一个Spring Data JPA测试,以List
形式加载所有用户,并断言结果中的所有用户都大于20岁。
Spring Data提供了多种查询方式,这里我们将使用query方法构建查询。
我们将使用此query方法加载List
中的用户:
List<User> findByAgeGreaterThan20();
现在,让我们编写一个测试用例看看它是如何工作的:
@Test
public void whenAgeIs20_thenItShouldReturnAllUsersWhoseAgeIsGreaterThan20InAList() {
List<User> users = userRepository.findByAgeGreaterThan(20);
assertThat(users).isNotEmpty();
assertThat(users.stream().map(User::getAge).allMatch(age -> age > 20)).isTrue();
}
这个测试用例查询用户并断言所有用户都大于20岁。在这种情况下,客户端会一次性获取所有用户,而在查询完成后,底层数据库资源会被关闭,除非我们手动保持它们打开状态。
2.2. Stream
Stream
是数据流动的管道,它支持的一些中间方法会在数据流动过程中对数据执行操作。
虽然在List
中查询数据是获取集合的常见方式,但在作为数据库结果使用时,有一些关于其使用的注意事项,我们将在下一节中讨论。现在,让我们了解如何在Stream
中查询数据。
这次我们将使用这个query方法加载Stream
中的用户:
Stream<User> findByAgeGreaterThan20();
现在,让我们编写一个测试用例:
@Test
public void whenAgeIs20_thenItShouldReturnAllUsersWhoseAgeIsGreaterThan20InAStream() {
Stream<User> users = userRepository.findAllByAgeGreaterThan(20);
assertThat(users).isNotNull();
assertThat(users.map(User::getAge).allMatch(age -> age > 20)).isTrue();
}
我们可以清楚地看到,通过获取Stream
中的结果,可以直接对其进行操作。一旦得到第一个用户,客户端可以立即处理,而底层数据库资源在处理流中的所有用户时保持打开状态。
为了确保EntityManager
直到处理完Stream
中的所有结果才关闭,必须在Stream
查询上使用@Transactional
注解。此外,将Stream
查询包装在try-with-resources
语句中也是好的实践。
现在,既然我们了解了如何使用它们,接下来我们将探讨何时最适合使用每一种。
3. 何时使用
在适当的情境下使用Stream
和List
非常重要,因为在不适用的情况下使用它们可能会导致性能下降或意外行为。始终评估替代方案并选择最适合问题的一个。
List
适用于需要一次性获取所有结果的小型结果集,而Stream
更适合可以逐个处理的大结果集,并且当客户端需要Stream
而不是Collection
时。
在Stream
中查询数据时,如果数据库查询和中间Stream
方法都能产生相同的结果,我们应该优先选择数据库查询。
4. 总结
在这篇文章中,我们学习了在使用Spring Data Repositories时如何使用List
和Stream
。
我们也了解到,当客户端需要一次性获取所有结果时应使用List
,而在Stream
中,客户端可以在收到第一个结果后立即开始工作。我们还讨论了对底层数据库资源的影响以及何时最好使用它们。
本文中所有使用的代码示例可在GitHub上找到。