
1. Criteria查询的本质与定位Hibernate的Criteria查询是一种面向对象的查询方式它允许开发者在不编写HQL或SQL的情况下通过Java代码构建查询条件。这种查询方式最早出现在Hibernate 3.x版本中作为对传统HQL查询的补充。与直接拼接字符串的HQL不同Criteria API通过方法链式调用来构建查询这种设计模式在2006年发布的Hibernate 3.2中已经趋于成熟。在实际项目中我经常遇到需要动态构建查询条件的场景。比如用户在前端选择了多个筛选条件这些条件可能任意组合。如果使用HQL就需要通过字符串拼接来构建查询语句这不仅容易出错还可能引发SQL注入风险。而Criteria查询通过类型安全的方法调用完美解决了这些问题。2. Criteria API的核心架构解析2.1 关键组件与工作流程Criteria查询的核心是Criteria接口及其实现类。整个查询构建过程通常从Session.createCriteria()方法开始。以下是一个典型的工作流程Criteria criteria session.createCriteria(Employee.class); criteria.add(Restrictions.eq(department, IT)) .addOrder(Order.desc(hireDate)) .setMaxResults(10); ListEmployee employees criteria.list();这个例子中我们创建了一个查询Employee实体的Criteria对象添加了部门等于IT的条件按入职日期降序排列并限制返回10条记录。整个过程完全通过Java方法调用完成没有出现任何SQL片段。2.2 条件构造的三种范式Criteria查询支持多种条件构造方式我总结为三种主要范式基本条件Restrictions等值查询Restrictions.eq(property, value)范围查询Restrictions.between(age, 20, 30)模糊查询Restrictions.like(name, 张%)组合条件LogicalExpressionRestrictions.and( Restrictions.ge(salary, 5000), Restrictions.or( Restrictions.eq(title, Engineer), Restrictions.eq(title, Senior Engineer) ) )关联查询CriteriaCriteria criteria session.createCriteria(Order.class); criteria.createAlias(customer, c) .add(Restrictions.eq(c.level, VIP));3. 高级查询特性深度剖析3.1 投影与聚合函数Criteria查询支持丰富的投影操作这是它比HQL更灵活的地方之一。通过Projections类可以实现criteria.setProjection(Projections.projectionList() .add(Projections.rowCount()) .add(Projections.avg(salary)) .add(Projections.groupProperty(department)) );这种聚合查询在报表统计场景非常有用。我曾经在一个绩效统计模块中用这种方式替代了原来复杂的原生SQL代码可读性提高了60%以上。3.2 分页与排序的最佳实践分页查询是业务系统的常见需求Criteria提供了优雅的实现方式criteria.setFirstResult(20) // 从第20条记录开始 .setMaxResults(10) // 取10条记录 .addOrder(Order.desc(createTime));这里有个实际项目中的经验当处理大数据量分页时应该避免使用setFirstResult因为Hibernate会先获取全部结果再截取。这种情况下改用ScrollableResults或基于索引的条件过滤会更高效。4. 性能优化与陷阱规避4.1 N1查询问题的解决方案与HQL类似Criteria查询也可能遇到N1问题。通过setFetchMode可以指定关联加载策略criteria.setFetchMode(orders, FetchMode.JOIN);但要注意过度使用JOIN可能导致笛卡尔积问题。我的经验法则是对一对多关联优先使用SUBSELECT策略对多对一关联使用JOIN策略更合适。4.2 缓存机制的适配Criteria查询默认会使用Hibernate的二级缓存但有些情况下需要特殊处理criteria.setCacheable(true) .setCacheRegion(employeeQueries);在最近的一个电商项目中我们发现缓存配置不当导致商品库存显示不一致。后来通过为不同的查询设置不同的cacheRegion解决了这个问题。5. 与JPA Criteria的对比与迁移随着JPA标准的普及Hibernate Criteria API逐渐演进为JPA Criteria API。两者主要区别在于包结构不同Hibernate:org.hibernate.CriteriaJPA:javax.persistence.criteria.CriteriaBuilder类型安全增强 JPA Criteria通过元模型Metamodel提供了编译期类型检查CriteriaBuilder cb em.getCriteriaBuilder(); CriteriaQueryEmployee q cb.createQuery(Employee.class); RootEmployee emp q.from(Employee.class); q.select(emp).where(cb.equal(emp.get(Employee_.name), 张三));对于新项目我建议直接使用JPA Criteria。但维护老系统时理解Hibernate Criteria仍然很有必要。6. 实际项目中的典型应用场景6.1 动态查询构建器模式这是我经常使用的一种设计模式特别适合复杂筛选条件public class EmployeeQueryBuilder { private ListCriterion criteria new ArrayList(); public EmployeeQueryBuilder withName(String name) { if (name ! null) { criteria.add(Restrictions.like(name, name)); } return this; } public Criteria build(Session session) { Criteria criteria session.createCriteria(Employee.class); for (Criterion criterion : this.criteria) { criteria.add(criterion); } return criteria; } }这种模式在前端筛选条件不确定的系统中特别有用我在三个不同的CRM系统中都成功应用过。6.2 审计日志查询优化在审计日志查询中Criteria查询的链式调用可以优雅地处理各种时间范围组合public ListAuditLog searchLogs(Date from, Date to, String action) { Criteria criteria session.createCriteria(AuditLog.class); if (from ! null to ! null) { criteria.add(Restrictions.between(timestamp, from, to)); } else if (from ! null) { criteria.add(Restrictions.ge(timestamp, from)); } else if (to ! null) { criteria.add(Restrictions.le(timestamp, to)); } if (action ! null) { criteria.add(Restrictions.eq(action, action)); } return criteria.list(); }7. 常见问题排查指南7.1 别名使用陷阱在关联查询中错误的别名使用是常见错误// 错误示例 criteria.createAlias(department, dept) .add(Restrictions.eq(name, IT)); // 这里的name是哪个实体的 // 正确写法 criteria.createAlias(department, dept) .add(Restrictions.eq(dept.name, IT));7.2 延迟加载异常在Web应用中常见的LazyInitializationException可以通过以下方式避免criteria.setFetchMode(subordinates, FetchMode.JOIN);或者在事务边界内完成所有数据加载。我通常建议在DAO层就处理好所有必要的数据加载而不是让延迟加载问题渗透到表现层。8. 现代替代方案与演进方向虽然Hibernate Criteria仍然可用但新的项目我更推荐QueryDSL提供更友好的API和更好的类型安全Spring Data JPA通过方法名自动生成查询JOOQ对复杂SQL场景更友好特别是在微服务架构下这些替代方案往往能提供更好的开发体验。不过理解Criteria查询的原理对于深入掌握ORM技术仍然很有价值。