1. 概述

在这个简短的教程中,我们将探讨在Spring Data JPA中获取最后一条记录的不同方法。首先,我们将了解如何使用衍生查询方法。然后,我们将研究如何使用@Query注解实现相同的功能。

2. 准备工作

首先,让我们创建并初始化我们想要查询的表。 我们从创建一个Post实体类开始:

@Entity
public class Post {

    @Id
    private Long id;
    private String title;
    private LocalDate publicationDate;

    // standard getters and setters

}

@Entity表明被注解的类表示数据库中的一个表。同样,@Id注解定义了主键。

为了简化,我们将使用内存数据库H2。首先,添加一个基本的SQL脚本以创建与Post类关联的post表:

DROP TABLE IF EXISTS post;
CREATE TABLE post(
    id INT PRIMARY KEY,
    title VARCHAR(200),
    publication_date DATE
)

接下来,为表填充数据:

INSERT INTO post (id, title, publication_date) VALUES(1, 'Facebook post', '2020-11-10');
INSERT INTO post (id, title, publication_date) VALUES(2, 'Instagram post', '2020-12-24');
INSERT INTO post (id, title, publication_date) VALUES(3, 'Twitter post', '2023-01-10');
INSERT INTO post (id, title, publication_date) VALUES(4, 'tiktok post', '2023-03-18');
INSERT INTO post (id, title, publication_date) VALUES(5, 'Pinterest post', '2023-09-09');

如图所示,这里的最后一条记录是id为5的那一条。因此,为了达到获取表中最后一条记录的目标,我们将根据publication_date倒序排列记录。然后,我们将使用Spring Data JPA的方法从排序结果中获取第一条记录。这样,我们就能得到表的最后一条记录。

3. 使用衍生查询方法

Spring Data JPA因其衍生查询方法而受到赞誉。这个特性提供了一种方便的方式,无需手动编写SQL语句,即可从方法名称生成查询。

Spring Data JPA并没有直接提供获取最后一条记录的方法。然而,它提供了简单的方法来从一组记录的开头检索数据。

例如,我们可以使用findFirst前缀创建一个衍生查询,该查询从结果集中获取第一条记录。让我们看看它是如何工作的:

public interface PostRepository extends JpaRepository<Post, Integer> {

    Post findFirstByOrderByPublicationDateDesc();

}

方法名称findFirstByOrderByPublicationDateDesc()的每一部分都有其含义。动词“find”告诉Spring Data JPA生成一个选择查询,而“First”表示从结果集中获取第一条记录。

此外,“OrderByPublicationDateDesc”表示我们希望按publicationDate属性的降序对记录进行排序。

Spring Data JPA智能地解释方法名称。它首先按照发布日期的降序对帖子进行排序。这样,它将最后一条记录放在结果的开头。

然后,它解释findFirst表示从排序后的记录返回第一个元素。因此,我们得到了表的最后一条记录。

现在,让我们添加一个测试用例以确认一切按预期工作:

@Test
void givenPosts_whenUsingFindFirstDerivedQuery_thenReturnLastPost() {
    Post post = postRepository.findFirstByOrderByPublicationDateDesc();

    assertNotNull(post);
    assertEquals(5, post.getId());
}

我们可以看到测试成功通过。

同样,我们也可以使用findTop关键字达到相同的效果。我们可以互换使用firstFirstfindTop,没有任何问题:

Post findTopByOrderByPublicationDateDesc();

最后,为findTopByOrderByPublicationDateDesc()方法创建另一个测试用例:

@Test
void givenPosts_whenUsingFindTopDerivedQuery_thenReturnLastPost() {
    Post post = postRepository.findTopByOrderByPublicationDateDesc();

    assertNotNull(post);
    assertEquals(5, post.getId());
}

如上所示,测试用例成功通过。

4. 使用@Query注解

另一种解决方案是使用@Query注解将一个方法绑定到一个查询,该查询用于获取最后一条记录。默认情况下,@Query接受JPQL查询。因此,让我们在PostRepository中添加另一个名为findLastPost()的方法,并使用@Query指定获取最后一条帖子的查询:

@Query("SELECT p FROM Post p ORDER BY p.publicationDate DESC LIMIT 1")
Post findLastPost();

简单来说,我们选择了按发布日期降序排序的帖子,然后使用LIMIT 1只获取一条帖子。返回的帖子代表了最后一条记录。

一如既往,我们添加一个测试用例来测试新方法:

@Test
void givenPosts_whenUsingQueryAnnotation_thenReturnLastPost() {
    Post post = postRepository.findLastPost();

    assertNotNull(post);
    assertEquals(5, post.getId());
}

不出所料,最后一条记录是id为5的帖子。

5. 总结

在这篇教程中,我们探讨了使用Spring Data JPA从特定表中获取最后一条记录的不同方法。首先,我们了解了如何使用衍生查询方法。然后,我们在@Query注解中编写了一个JPQL查询,获得了相同的结果。

完整的代码示例可以在GitHub上找到。