QBC条件查询实战,5个代码示例解决复杂筛选问题
上周团队新来的实习生小王悄悄问我:“为什么用Hibernate的QBC写查询,明明代码没报错,结果却少了几条数据?”我一看他的代码就乐了——Restrictions.gt("age", 30)后面漏了个分页参数。这种踩坑经历,每个Java开发者可能都遇到过。今天咱们就用5个真实场景的代码示例,把QBC条件查询那点事儿掰扯明白。
一、基础条件查询:比你想的更灵活
很多教程一上来就讲Restrictions.eq(),但实战中更常用的是动态条件拼接。比如电商后台的订单筛选功能:
java运行复制// 根据用户输入动态构建查询 Criteria criteria = session.createCriteria(Order.class); if (StringUtils.isNotBlank(orderNo)) { criteria.add(Restrictions.like("orderNo", "%"+orderNo+"%")); } if (startDate != null) { criteria.add(Restrictions.ge("createTime", startDate)); } // 执行查询 Listorders = criteria.list();
关键细节:
Restrictions.ge()(大于等于)比gt()(大于)更常用,避免漏掉边界数据模糊查询时别手写百分号!用
MatchMode.ANYWHERE更安全:java运行复制
Restrictions.like("productName", keyword, MatchMode.ANYWHERE)
去年优化某物流系统时,就因为漏了MatchMode导致查询超时——数据库全表扫描了20万条记录,你懂的。
二、多条件组合:这样避开逻辑陷阱
当查询条件需要AND/OR混合时,新手常写出隐性BUG。比如要查“金额>1000元且已付款,或VIP用户的订单”:
java运行复制// 错误写法!VIP条件会被忽略 criteria.add(Restrictions.gt("amount", 1000)) .add(Restrictions.eq("status", "PAID")) .add(Restrictions.eq("isVip", true)); // 正确姿势:用Disjunction包装OR条件 Disjunction orCondition = Restrictions.disjunction(); orCondition.add(Restrictions.and( Restrictions.gt("amount", 1000), Restrictions.eq("status", "PAID") )); orCondition.add(Restrictions.eq("isVip", true)); criteria.add(orCondition);
避坑指南:
Restrictions.disjunction()相当于SQL的OR嵌套
Restrictions.and()时,先写子条件再组装,避免优先级错乱复杂条件超过3层?建议改用
DetachedCriteria拆分逻辑
三、分页+排序:性能优化的隐藏技巧
你以为setFirstResult()和setMaxResults()就是分页全部?试试这个千万级数据场景的优化方案:
java运行复制criteria.setFirstResult((pageNum-1)*pageSize) .setMaxResults(pageSize) .addOrder(Order.desc("createTime")); // 按时间倒序 // 加上这句!查询效率翻倍 criteria.setFetchMode("user", FetchMode.JOIN);
为什么有效:
默认分页会触发N+1查询(先查主表再循环查关联表)
setFetchMode强制用JOIN一次性加载关联对象,减少数据库往返
还记得去年做政务系统审计模块时,没加这行代码导致分页查询从200ms暴跌到2秒——DBA差点把我工位拆了。
四、统计查询:90%人没用好Projections
分组统计别再手写SQL了!QBC的Projections能优雅实现:
java运行复制// 统计各部门的薪资最大值和平均值 criteria.setProjection(Projections.projectionList() .add(Projections.groupProperty("dept")) .add(Projections.max("salary")) .add(Projections.avg("salary")) ); // 返回List List
输出结果处理技巧:
用
Alias给统计字段起别名,避免object[1]这种魔法数:java运行复制
.add(Projections.max("salary"), "maxSalary")复杂统计?试试
DetachedCriteria子查询
五、QBC vs HQL:我的选择建议
总有人争论该用哪个,其实场景决定工具:
选QBC当:
条件动态变化(如后台筛选器)
需要强类型检查(编译期防手误)
关联查询层级深(避免HQL的JOIN语句膨胀)
选HQL当:
固定复杂查询(如报表SQL)
需要批量更新/删除
跨多表聚合计算
上周重构旧系统时,把一段80行的HQL改成QBC后——团队新人直呼“终于能看懂了”!
最后说两句
QBC就像乐高积木,灵活但依赖组装逻辑。刚入门时觉得不如HQL直接,但用熟后会发现:
条件越复杂,QBC的可读性优势越明显
动态查询的代码量能减少30%
类型安全让调试时间减半
建议存好这些示例代码,下次写查询前翻出来对照下。毕竟,少走弯路就是高效——你说对吧?
(示例工程已上传GitHub,需要源码可私信~)