java中怎么实现条件查询
- 后端开发
- 2025-08-18
- 5
Java中实现条件查询是开发过程中常见的需求,尤其在涉及数据库操作时,以下是几种主流的技术方案及其具体实现方式:
基于MyBatis-Plus的QueryWrapper实现
MyBatis-Plus作为MyBatis的增强工具,提供了QueryWrapper
类用于构建动态SQL条件,其核心优势在于链式调用语法和类型安全的API设计。
QueryWrapper<User> qw = new QueryWrapper<>(); qw.eq("age", 25) // 等于条件 .ne("name", "张三") // 不等于 .gt("salary", 10000) // 大于 .like("address", "北京");// 模糊匹配 List<User> users = userMapper.selectList(qw);
此方式支持组合多个条件(AND逻辑),若需OR关系可改用or()
方法分支,还能处理排序、分组等复杂场景,如qw.orderByAsc("create_time")
实现升序排列,该框架还自动防止SQL注入风险,适合大多数企业级应用。
Spring Data JPA的条件构造器
对于使用Hibernate底层的JPA项目,可通过CriteriaBuilder
创建类型安全的动态查询,典型流程如下:
// 获取实体管理器并启动事务(省略) CriteriaBuilder cb = entityManager.getCriteriaBuilder(); CriteriaQuery<User> cq = cb.createQuery(User.class); Root<User> root = cq.from(User.class); Predicate predicate = cb.conjunction(); // 初始化为AND连接 List<Predicate> conditions = new ArrayList<>(); if (StringUtils.isNotBlank(searchKeyword)) { conditions.add(cb.like(root.get("username"), "%" + searchKeyword + "%")); } if (minAge != null) { conditions.add(cb.ge(root.get("age"), minAge)); } // 将所有条件用AND合并 predicate = cb.and(conditions.toArray(new Predicate[0])); cq.where(predicate); TypedQuery<User> query = entityManager.createQuery(cq); return query.getResultList();
这种方式的优势在于完全脱离原生SQL,利用JPA规范实现跨数据库兼容,但学习曲线相对较陡。
原生JDBC与PreparedStatement
当需要极致性能或特殊语法支持时,可直接编写SQL并预编译参数:
StringBuilder sql = new StringBuilder("SELECT FROM users WHERE 1=1"); // 基准占位符技巧 List<Object> params = new ArrayList<>(); if (filter.getName() != null) { sql.append(" AND name = ?"); params.add(filter.getName()); } if (filter.getDeptId() > 0) { sql.append(" AND department_id < ?"); params.add(filter.getDeptId()); } try (PreparedStatement pstmt = connection.prepareStatement(sql.toString())) { for (int i = 0; i < params.size(); i++) { pstmt.setObject(i + 1, params.get(i)); // 注意索引从1开始 } ResultSet rs = pstmt.executeQuery(); // 遍历结果集... }
特别注意要手动处理参数顺序与防SQL注入,建议配合连接池使用以提升效率,此方案适合对性能要求严苛的场景,但维护成本较高。
MongoDB模板化查询(Spring Data)
针对NoSQL数据库如MongoDB,Spring提供专门的模板类:
BasicQuery basicQuery = new BasicQuery(new Criteria().andOperator( Criteria.where("status").is(ActiveStatus.NORMAL), Criteria.where("createTime").lt(new Date()) )); Query query = new Query(basicQuery).with(Sort.by(Direction.DESC, "updateTime")); List<Document> results = mongoTemplate.find(query, Document.class, "collectionName");
通过Criteria
对象的组合,可以构建复杂的嵌套条件,同时支持地理空间索引等特色功能,这种声明式的写法降低了驱动不同数据库的成本。
方案对比表
特性 | MyBatis-Plus | JPA | JDBC | Spring Data MongoDB |
---|---|---|---|---|
学习难度 | 低 | 中高 | 中 | 中 |
SQL依赖程度 | 无需 | 无需 | 必须 | 无需 |
性能优化空间 | 中等 | 较低 | 高 | 中等 |
跨数据库兼容性 | 依赖方言注解 | 优秀 | 优秀 | 特定于MongoDB |
复杂条件表达能力 | 强 | 极强 | 强 | 强 |
社区生态支持 | 国内主流 | 国际标准 | 基础协议 | 官方推荐 |
实践建议
- 优先选择ORM框架:除非有特殊需求,否则推荐使用MyBatis-Plus或JPA等成熟方案,它们能有效减少重复代码并提升安全性。
- 参数化必做:任何情况下都应避免字符串拼接SQL,始终使用预编译语句或框架提供的参数绑定机制。
- 分页标配:所有查询都应默认携带分页参数,防止全表扫描导致的性能雪崩,例如MyBatis-Plus的
Page<T>
对象天然支持物理分页。 - 日志监控:开启慢查询日志以便持续优化热点SQL,特别是动态生成的语句更需关注执行计划。
FAQs:
Q1: 如何动态切换AND/OR逻辑?
A: 在MyBatis-Plus中使用or()
方法切换分支,如qw.or().eq("field1", val1).or().eq("field2", val2)
;JPA则通过cb.or(predicateList)
实现多选一条件。
Q2: 大量组合条件导致代码臃肿怎么办?
A: 可采用规格设计模式(Specification pattern),将每个独立条件封装为单独类,再通过工厂模式组装复合条件,显著提升可读性和复用