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}] - 数据库数据:
name author price book1-name author2 200 book1-name author2 300
使用上述任意方案,都会正确匹配到第二行数据(book1-name, author2, 300)。
内容的提问来源于stack exchange,提问作者WonderWoman
相关产品推荐
相关产品推荐

