返回

Spring Boot 和 Spring Data JPA 帖子分页:带左连接的排除特定报告筛选

mysql

Spring Boot和Spring Data JPA:带左连接的帖子分页和筛选以排除特定报告

简介

在本文中,我们将探讨一种场景,我们需要使用Spring Boot和Spring Data JPA从数据库中检索分页帖子的列表。独特的要求是在获取帖子时排除已被特定用户举报的帖子。我们将使用左连接操作来实现此过滤。

数据库架构

我们假设以下数据库架构:

CREATE TABLE posts (
  id BINARY(16) NOT NULL,
  posts VARCHAR(5000) DEFAULT NULL,
  created_at DATETIME(6) DEFAULT NULL,
  updated_at DATETIME(6) DEFAULT NULL,
  user_id BINARY(16) DEFAULT NULL,
  PRIMARY KEY (id),
  FOREIGN KEY (user_id) REFERENCES users (id)
);

CREATE TABLE post_reports (
  id BINARY(16) NOT NULL,
  reported_at DATETIME(6) DEFAULT NULL,
  reported_by VARCHAR(255) DEFAULT NULL,
  reported_reason VARCHAR(255) DEFAULT NULL,
  updated_at DATETIME(6) DEFAULT NULL,
  updated_by VARCHAR(255) DEFAULT NULL,
  post_id BINARY(16) DEFAULT NULL,
  PRIMARY KEY (id),
  FOREIGN KEY (post_id) REFERENCES posts (id)
);

实体类

表的相应JPA实体如下:

@Entity
public class Post {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @UuidGenerator(style = UuidGenerator.Style.TIME)
    private UUID id;
    
    @Column(length = 5000)
    private String comment;
    
    @ManyToOne
    @JoinColumn(name = "user_id")
    private User user;
    
    // ... other fields and methods
}

@Entity
public class PostReport {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @UuidGenerator(style = UuidGenerator.Style.TIME)
    private UUID id;
    
    @ManyToOne
    @JoinColumn(name = "post_id")
    private Post post;
    
    @Column(name = "reported_by")
    private String reportedBy;
    
    // ... other fields and methods
}

JPA查询

以下JPA查询通过在postspost_reports表之间执行左连接来检索不同的帖子,并过滤掉已被特定用户举报的帖子:

@Query(
      value =
          "SELECT DISTINCT p.* FROM posts AS p LEFT JOIN post_reports AS pr ON p.id=pr.post_id WHERE (pr.reported_by IS NULL OR pr.reported_by!=:reportedBy) order by p.created_at",
      countQuery =
          "SELECT COUNT(DISTINCT p.*) FROM posts AS p LEFT JOIN FETCH post_reports AS pr ON p.id= pr.post_id WHERE (pr.reported_by IS NULL OR pr.reported_by!=:reportedBy)",
      nativeQuery = true)
  Page<Post> findAllByReportedByNullOrReportedByNot(
      @Param("reportedBy") String reportedBy, Pageable pageable);

解释

  • 该查询使用LEFT JOINpostspost_reports表基于post_id列进行组合。
  • WHERE子句会过滤掉post_reports表中reported_by列为NULL或不匹配指定reportedBy参数的帖子。
  • 该查询按created_at列降序排列结果。
  • @Query注解指定了JPQL查询、其计数查询,以及是否以原生查询形式执行。
  • findAllByReportedByNullOrReportedByNot方法接收一个String reportedBy和一个Pageable对象作为参数,并返回一个Post对象Page

用法

要使用此查询,你可以将PostRepository接口注入到你的服务或控制器中,然后调用findAllByReportedByNullOrReportedByNot方法:

@Autowired
private PostRepository postRepository;

// ...

Page<Post> posts = postRepository.findAllByReportedByNullOrReportedByNot(reportedBy, pageable);

Page对象包含分页结果,可用于访问当前页、总页数、总元素数以及Post对象的实际列表。

结论

在本文中,我们展示了如何使用Spring Boot和Spring Data JPA对帖子进行分页和过滤,通过左连接操作排除了被特定用户举报的帖子。这种方法提供了一种灵活而有效的方式来从复杂数据库结构中检索数据。

常见问题解答

  1. 此查询可以用于其他数据库系统吗?
    是的,该查询可以使用JPQL,它与大多数主要数据库系统兼容。但是,你可能需要根据特定数据库的方言对语法进行一些调整。

  2. 如何优化查询以提高性能?
    你可以使用索引来优化查询,特别是在post_reports表上的post_idreported_by列。此外,你可以使用批处理或缓存来减少数据库调用的次数。

  3. 我可以使用此方法来过滤其他类型的报告吗?
    是的,此方法可以推广到其他类型的报告,如评论、用户和其他可报告的实体。

  4. 如何处理分页结果?
    你可以使用Page对象的便捷方法来获取当前页、总页数和总元素数。你还可以使用流式API或其他框架特定的方法来进一步处理结果。

  5. 是否可以将此查询与其他查询组合起来?
    是的,你可以将此查询与其他查询组合起来,以创建更复杂的筛选和排序标准。Spring Data JPA提供了强大的查询方法,使你能够轻松地组合多个查询条件。