Spring Data 3 中的新 CRUD Repository 接口
1、概览
本文将带你了解 Spring Data 3 中引入的新 Repository
接口。
Spring Data 3 引入了基于 List
的 CRUD Repository
接口,可用于替换返回 Iterable
的现有 CRUD Repository
接口。此外,分页和排序接口默认不继承原始 CRUD Repository
,而是由用户自己选择。接下来看看这些接口与现有接口有何不同,以及如何使用它们。
2、项目设置
首先创建一个 Spring Boot 应用,其中包含一个简单的实体和将使用新接口的 Repository。
2.1、依赖
首先,为项目添加所需的 spring-boot-starter-data-jpa
依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>3.2.3</version>
</dependency>
除此之外,还要配置数据库。可以使用任何 SQL 数据库,本文将使用 H2 内存数据库:
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
2.2、Entity
创建一个 Book
实体:
@Entity
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String author;
private String isbn;
// 构造器、Getter、Setter
}
有了实体后,来看看如何使用新接口与数据库交互。
3、基于 List 的 Repository
Spring Data 3 引入了一组新的 CRUD Repository 接口,可返回实体列表。这些接口与现有接口类似,只是它们返回的是 List
而不是 Iterable
。这使我们能够使用 List
接口的高级方法,如 get()
和 indexOf()
。
3.1、Spring Data 3 中新增了三个接口
ListCrudRepository
接口提供了基本 CRUD 操作方法,如 save()
、delete()
和 findById()
。ListCrudRepository
与基于 Iterable
的对应 Repository 的主要区别在于,返回值现在是 List
,这使我们可以对返回的数据执行更高级的操作。
ListQuerydslPredicateExecutor
接口提供了使用 Querydsl
Predicate
执行查询的方法。Querydsl 是一个允许在 Java 中构建类型安全的 SQL 类查询的框架。通过 ListQuerydslPredicateExecutor
,我们可以执行 Querydsl 查询并以 List
形式返回结果。
ListQueryByExampleExecutor
接口提供了使用 Example 实体执行查询并以 List
形式返回结果的方法。Example 实体是指包含我们想用来搜索其他实体的值的实体。例如,如果我们有一个 title
为 Spring Data
的 Book
实体,我们就可以创建一个 title
为 Spring Data
的示例实体,并用它来搜索 title
相同的其他 Book
。
3.2、ListCrudRepository
来详细看看 ListCrudRepository
接口。首先,创建一个使用该接口与数据库交互的 Repository:
@Repository
public interface BookListRepository extends ListCrudRepository<Book, Long> {
List<Book> findBooksByAuthor(String author);
}
上述 Repository 继承了 ListCrudRepository
接口,为我们提供了基本的 CRUD 方法。我们可以使用现有的 Repository 方法来保存、删除和查找数据库中的 Book
。
除这些方法外,还自定义了 findBooksByAuthor()
方法,用于按 author
查找 Book
。
3.3、使用基于 List 的 Repository
来看看如何使用该 Repository 与数据库交互:
@SpringBootTest
public class BookListRepositoryIntegrationTest {
@Autowired
private BookListRepository bookListRepository;
@Test
public void givenDbContainsBooks_whenFindBooksByAuthor_thenReturnBooksByAuthor() {
Book book1 = new Book("Spring Data", "John Doe", "1234567890");
Book book2 = new Book("Spring Data 2", "John Doe", "1234567891");
Book book3 = new Book("Spring Data 3", "John Doe", "1234567892");
bookListRepository.saveAll(Arrays.asList(book1, book2, book3));
List<Book> books = bookListRepository.findBooksByAuthor("John Doe");
Assert.assertEquals(3, books.size());
}
}
首先创建了三个 Boot
实体,并将它们保存到数据库中。然后,使用 findBooksByAuthor()
方法查找 author
为 John Doe
的所有 Book
。最后,验证返回的 List
是否包含所创建的三个 Boot
实体。
注意,我们在返回的 List
上调用 了 size()
方法。如果 Repository 使用基于 Iterable
的接口,就不可能这样做,因为 Iterable
接口未提供 size()
方法。
4、排序接口
为了能够使用新的基于 List
的接口,Spring Data 3 必须对现有的排序接口进行更改。 PagingAndSortingRepository
不再继承旧的 CrudRepository
。相反,用户可以选择在继承排序接口的同时继承新的基于 List
的接口或基于 Iterable
的接口。
4.1、PagingAndSortingRepository
来看看,PagingAndSortingRepository
接口,创建一个使用该接口与数据库交互的 Repository:
@Repository
public interface BookPagingAndSortingRepository extends PagingAndSortingRepository<Book, Long>, ListCrudRepository<Book, Long> {
List<Book> findBooksByAuthor(String author, Pageable pageable);
}
上述 Repository 继承了 ListCrudRepository
接口,该接口为我们提供了基本的 CRUD 方法。除此之外,还继承了 PagingAndSortingRepository
接口,它为我们提供了排序和分页方法。
在 Spring Data 的旧版本中,不需要明确继承 CrudRepository
接口。只有排序和分页接口就足够了。这里还定义了一个名为 findBooksByAuthor()
的新方法,它接收一个 Pageable
参数并返回一个 List<Book>
。
接下来,看看如何使用该方法对结果进行排序和分页。
4.2、使用排序 Repository 接口
使用该 Repository 与数据库交互:
@SpringBootTest
public class BookPagingAndSortingRepositoryIntegrationTest {
@Autowired
private BookPagingAndSortingRepository bookPagingAndSortingRepository;
@Test
public void givenDbContainsBooks_whenfindBooksByAuthor_thenReturnBooksByAuthor() {
Book book1 = new Book("Spring Data", "John Doe", "1234567890");
Book book2 = new Book("Spring Data 2", "John Doe", "1234567891");
Book book3 = new Book("Spring Data 3", "John Doe", "1234567892");
bookPagingAndSortingRepository.saveAll(Arrays.asList(book1, book2, book3));
Pageable pageable = PageRequest.of(0, 2, Sort.by("title").descending());
List<Book> books = bookPagingAndSortingRepository.findBooksByAuthor("John Doe", pageable);
Assert.assertEquals(2, books.size());
Assertions.assertEquals(book3.getId(), books.get(0).getId());
Assertions.assertEquals(book2.getId(), books.get(1).getId());
}
}
和之前一样,我们首先创建了三个 Book
实体,并将它们保存到数据库中。然后,使用 findBooksByAuthor()
方法查找 author
为 John Doe
的所有书籍。但这次,我们向该方法传递了一个 Pageable
对象,按 title
降序排序,并只返回前两个结果。
最后,验证返回的 List
是否包含之前创建的两个 Book
实体。还验证了 Book
是按 title
降序排序的,因此 title
为 Spring Data 3
的书首先返回,标题为 Spring Data 2
的书其次返回。
4.3、其他排序接口
除 PagingAndSortingRepository
接口外,还更改了以下接口:
ReactiveSortingRepository
不再继承自ReactiveCrudRepository
CoroutineSortingRepository
不再继承自CoroutineCrudRepository
RxJavaSortingRepository
不再继承自RxJavaCrudRepository
5、总结
本文介绍了在 Spring Data 3 中新增的基于 List
的 ListCrudRepository
接口,以及如何使用这些接口与数据库进行交互。还介绍了对现有排序接口所做的更改,以便能够同时使用新的 ListCrudRepository
的接口。
Ref:https://www.baeldung.com/spring-data-3-crud-repository-interfaces