You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot 3.1.1中如何单次调用实现Book实体批量多条件查询?

Spring Boot 3.1.1 中JPA批量多条件查询实现方案

先修正原代码中的明显错误:

  • JPARepository泛型参数应为JPARepository<BookEntity, Integer>(实体类+主键类型)
  • JPQL中实体类名需与Java类名一致,应为BookEntity而非小写的bookEntity
  • @Query注解的字符串格式需修正,避免语法错误

针对传入List<BookDTO>实现批量多条件查询,以下是三种可行方案:

方案一:JPQL行值表达式查询

利用数据库支持的行值IN子句,直接匹配多字段组合,代码简洁高效:

@Repository
public interface BookRepository extends JPARepository<BookEntity, Integer> {

    @Query("SELECT b FROM BookEntity b WHERE " +
           "(:bookDTOs IS EMPTY OR " +
           " (b.name, b.isbn, b.author, b.price) IN " +
           " (SELECT dto.name, dto.isbn, dto.author, dto.price FROM :bookDTOs dto))")
    List<BookEntity> findByMultipleBookDTOs(@Param("bookDTOs") List<BookDTO> bookDTOs);
}

注意事项:

  • 需数据库支持行值表达式(MySQL 8.0+、PostgreSQL、Oracle 12c+均支持)
  • DTO的属性需与实体类属性完全对应,确保映射正确
  • 若bookDTOs为空,会返回所有数据,可根据需求调整为空时的逻辑

方案二:Criteria API动态构建查询

适合条件不固定、需动态调整的场景,完全基于JPA标准API,不依赖数据库特定语法:

1. 定义自定义Repository接口

public interface BookRepositoryCustom {
    List<BookEntity> findByMultipleBookDTOs(List<BookDTO> bookDTOs);
}

2. 实现自定义接口

@Repository
public class BookRepositoryImpl implements BookRepositoryCustom {

    private final EntityManager em;

    public BookRepositoryImpl(EntityManager em) {
        this.em = em;
    }

    @Override
    public List<BookEntity> findByMultipleBookDTOs(List<BookDTO> bookDTOs) {
        if (bookDTOs == null || bookDTOs.isEmpty()) {
            return Collections.emptyList();
        }

        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<BookEntity> query = cb.createQuery(BookEntity.class);
        Root<BookEntity> root = query.from(BookEntity.class);

        // 构建每个DTO对应的条件组,多个组用OR连接
        List<Predicate> predicateGroups = new ArrayList<>();
        for (BookDTO dto : bookDTOs) {
            Predicate group = cb.and(
                cb.equal(root.get("name"), dto.getName()),
                cb.equal(root.get("isbn"), dto.getIsbn()),
                cb.equal(root.get("author"), dto.getAuthor()),
                cb.equal(root.get("price"), dto.getPrice())
                // 追加其他需要匹配的字段
            );
            predicateGroups.add(group);
        }

        query.where(cb.or(predicateGroups.toArray(new Predicate[0])));
        return em.createQuery(query).getResultList();
    }
}

3. 让主Repository继承自定义接口

@Repository
public interface BookRepository extends JPARepository<BookEntity, Integer>, BookRepositoryCustom {
    // 原有方法...
}

方案三:原生SQL查询

性能最优但耦合数据库,适合对性能要求极高且数据库固定的场景:

@Repository
public interface BookRepository extends JPARepository<BookEntity, Integer> {

    @Query(value = "SELECT * FROM book_entity b WHERE " +
                   "(b.name, b.isbn, b.author, b.price) IN " +
                   "(SELECT unnest(ARRAY[:names]), unnest(ARRAY[:isbns]), unnest(ARRAY[:authors]), unnest(ARRAY[:prices]))",
           nativeQuery = true)
    List<BookEntity> findByMultipleBookDTOs(@Param("names") List<String> names,
                                            @Param("isbns") List<String> isbns,
                                            @Param("authors") List<String> authors,
                                            @Param("prices") List<Integer> prices);
}

注意:不同数据库的集合展开语法不同,上述示例为PostgreSQL的unnest用法,MySQL需用VALUES子句或其他方式构造临时表。

示例验证

针对你的测试场景:

  • 查询条件DTO列表:[{"name":"book1-name", "author":"author1", "price":200}, {"name":"book1-name", "author":"author2", "price":300}]
  • 数据库数据:
    nameauthorprice
    book1-nameauthor2200
    book1-nameauthor2300

使用上述任意方案,都会正确匹配到第二行数据(book1-name, author2, 300)。

内容的提问来源于stack exchange,提问作者WonderWoman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 02:03:24