Spring Data JDBC不支持Query by Example,可用什么方案替代?
解决方案
Spring Data JDBC本身没有内置Query By Example能力,可通过以下3种方案实现相同的动态等值查询效果:
方案1:集成Querydsl(最接近QBE的官方推荐方案)
Querydsl支持动态生成类型安全的查询,是Spring Data JDBC官方推荐的动态查询实现方式。
实现步骤:
- 引入Querydsl依赖,配置APT处理器自动生成查询实体类(Q类)
<!-- pom.xml 依赖配置 --> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-relational</artifactId> </dependency> <dependency> <groupId>com.querydsl</groupId> <artifactId>querydsl-sql</artifactId> </dependency> <dependency> <groupId>com.querydsl</groupId> <artifactId>querydsl-apt</artifactId> <scope>provided</scope> </dependency>
- 让OrderRepository继承
QuerydslPredicateExecutor接口
public interface OrderRepository extends CrudRepository<Order, Long>, QuerydslPredicateExecutor<Order> { }
- 动态拼接查询条件后执行查询
import com.querydsl.core.BooleanBuilder; import com.example.entity.QOrder; // 从JSON转换得到的Order实体 Order orderFromJson = ...; QOrder qOrder = QOrder.order; BooleanBuilder predicate = new BooleanBuilder(); // 逐个判断字段非空就加入查询条件 if (orderFromJson.getSomeField1() != null) { predicate.and(qOrder.someField1.eq(orderFromJson.getSomeField1())); } if (orderFromJson.getSomeField2() != null) { predicate.and(qOrder.someField2.eq(orderFromJson.getSomeField2())); } // 其余字段逻辑同理,字段较多时可通过反射批量判空组装条件 // 执行查询返回结果 Iterable<Order> orders = orderRepository.findAll(predicate);
方案2:@Query + SpEL动态条件(适合简单轻量场景)
如果不想引入额外依赖,可以用SpEL表达式在注解SQL里动态判断字段是否为空,为空就自动忽略该条件:
public interface OrderRepository extends CrudRepository<Order, Long> { @Query(""" SELECT * FROM order WHERE (:#{#order.someField1} IS NULL OR some_field1 = :#{#order.someField1}) AND (:#{#order.someField2} IS NULL OR some_field2 = :#{#order.someField2}) AND (:#{#order.someField3} IS NULL OR some_field3 = :#{#order.someField3}) AND (:#{#order.someField4} IS NULL OR some_field4 = :#{#order.someField4}) """, nativeQuery = true) List<Order> findAllByDynamicFilter(@Param("order") Order order); }
调用时直接传入从JSON转换得到的Order实体即可,null值字段对应的查询条件会自动失效。
方案3:JdbcTemplate手动拼接SQL(灵活度最高)
如果查询规则非常复杂,可以直接用JdbcTemplate动态拼接SQL和参数:
@Repository public class DynamicOrderRepository { @Autowired private JdbcTemplate jdbcTemplate; public List<Order> findByFilters(Order filter) { StringBuilder sql = new StringBuilder("SELECT * FROM order WHERE 1=1 "); List<Object> params = new ArrayList<>(); if (filter.getSomeField1() != null) { sql.append("AND some_field1 = ? "); params.add(filter.getSomeField1()); } if (filter.getSomeField2() != null) { sql.append("AND some_field2 = ? "); params.add(filter.getSomeField2()); } // 其余字段逻辑同理 return jdbcTemplate.query(sql.toString(), params.toArray(), BeanPropertyRowMapper.newInstance(Order.class)); } }
内容的提问来源于stack exchange,提问作者DozezQuest
相关产品推荐
相关产品推荐

