You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

antlr.NoViableAltException异常求助:Hibernate动态查询WHERE子句问题

兄弟,你这段代码里的问题其实挺典型的——直接把HQL字符串拼接和Hibernate Criteria API混着用了,这就是WHERE子句完全没生效的核心原因!我帮你拆解下具体问题,再给你两个靠谱的修复方案:

核心问题分析

1. 致命错误:混用HQL字符串与Criteria API

你一边在手动拼接HQL的query字符串,一边往criteria集合里加Criteria查询条件,最后还把criteria用String.join(" OR ", criteria)拼到HQL里——这完全是错误的用法!

Criteria API是Hibernate提供的独立于HQL的面向对象查询方式,你不能把Criteria对象直接当成HQL片段拼接,这么做只会让你的WHERE子句里塞满Criteria对象的toString()内容(类似org.hibernate.criterion.SimpleExpression@xxxx),根本不是数据库能解析的有效条件。

2. HQL拼接的语法漏洞

  • 你原HQL里Select字段的结尾和from之间没有空格!拼接后会变成workplaceNamefrom Employee emp,这本身就是语法错误,数据库直接解析失败。
  • 如果checkAllNotEmpty(data)为true,但所有参数都为空(比如用户没输入任何查询条件),你会拼接出WHERE ORDER BY的错误语法,同样会导致查询失败。

3. 参数绑定与条件脱节

你后面用q.setParameter()绑定了一堆参数,但这些参数对应的占位符(比如:id、:deptID)根本没出现在你拼接的HQL里——因为你根本没把正确的HQL条件片段加进去,参数绑定自然也完全无效。


修复方案(二选一即可)

方案一:纯HQL字符串拼接(适合熟悉SQL语法的场景)

用StringBuilder拼接HQL,手动添加条件片段,确保占位符和参数绑定对应:

try{
    // 注意开头Select字段后加空格,避免语法错误
    StringBuilder query = new StringBuilder("Select emp.employeeID,emp.firstName,emp.middleName,emp.lastName,pos.positionName,dept.deptName,work.workplaceName ");
    query.append("from Employee emp ");
    query.append("INNER JOIN Department dept ON emp.departmentID = dept.deptID ");
    query.append("INNER JOIN Position pos ON emp.positionID = pos.positionID ");
    query.append("INNER JOIN Workplace work ON emp.workplaceID = work.workplaceID ");

    List<String> hqlConditions = new ArrayList<>();
    if(checkAllNotEmpty(data)) {
        // 员工ID条件
        if(data.getEmployeeID() != null && !data.getEmployeeID().equals("")) {
            hqlConditions.add("emp.employeeID like :id");
            input_empID = true;
        }
        // 员工姓名条件(根据你的搜索逻辑拼接)
        if(data.getEmployeeName()!= null && !data.getEmployeeName().equals("")){
            if(searchbyOne){
                hqlConditions.add("(emp.firstName like :inputName OR emp.lastName like :inputName)");
            } else if(searchbyFandL){
                hqlConditions.add("(emp.firstName like :firstLastName AND emp.lastName like :firstLastName)");
            } else if(searchbyCompName){
                hqlConditions.add("concat(emp.firstName, ' ', emp.lastName) like :completeName");
            }
            input_empName = true;
        }
        // 部门条件
        if(data.getDepartmentID()!=0) {
            hqlConditions.add("emp.departmentID = :deptID");
            selected_dept = true;
        }
        // 职位条件
        if(data.getPositionID()!=0) {
            hqlConditions.add("emp.positionID = :posID");
            selected_pos = true;
        }
        // 工作地点条件
        if(data.getWorkplaceID()!=0) {
            hqlConditions.add("emp.workplaceID = :workID");
            selected_work = true;
        }
        // 只有当有条件时才拼接WHERE
        if(!hqlConditions.isEmpty()){
            query.append("WHERE ").append(String.join(" OR ", hqlConditions)).append(" ");
        }
    }
    query.append("ORDER BY emp.joinDate DESC");
    System.out.println("QUERY: " + query);
    
    Query q = session.createQuery(query.toString());
    // 绑定参数
    if(input_empID) {
        q.setParameter("id", "%" + data.getEmployeeID() + "%");
    }
    if(input_empName) {
        if(searchbyOne) q.setParameter("inputName", "%" + data.getEmployeeName() + "%");
        if(searchbyFandL) q.setParameter("firstLastName", "%" +firstLastName+ "%");
        if(searchbyCompName) q.setParameter("completeName", "%" +completeName+ "%");
    }
    if(selected_dept) {
        q.setParameter("deptID", data.getDepartmentID());
    }
    if(selected_pos) {
        q.setParameter("posID", data.getPositionID());
    }
    if(selected_work) {
        q.setParameter("workID", data.getWorkplaceID());
    }
    // 注意这里返回的是Object[]数组,因为你查的是多个字段
    employees = (List<Object[]>) q.list();
}catch(Exception e){
    e.printStackTrace();
}finally{
    session.close();
}
return employees;

方案二:纯Criteria API(更安全,避免SQL注入)

用Hibernate的Criteria API构建查询,完全不用手动拼接字符串,能自动处理语法和参数绑定:

try{
    CriteriaBuilder cb = session.getCriteriaBuilder();
    CriteriaQuery<Object[]> cq = cb.createQuery(Object[].class);
    Root<Employee> emp = cq.from(Employee.class);
    // 关联查询
    Join<Employee, Department> dept = emp.join("departmentID", JoinType.INNER);
    Join<Employee, Position> pos = emp.join("positionID", JoinType.INNER);
    Join<Employee, Workplace> work = emp.join("workplaceID", JoinType.INNER);

    // 选择需要返回的字段
    cq.select(cb.array(
        emp.get("employeeID"),
        emp.get("firstName"),
        emp.get("middleName"),
        emp.get("lastName"),
        pos.get("positionName"),
        dept.get("deptName"),
        work.get("workplaceName")
    ));

    List<Predicate> predicates = new ArrayList<>();
    if(checkAllNotEmpty(data)) {
        // 员工ID条件
        if(data.getEmployeeID() != null && !data.getEmployeeID().equals("")) {
            predicates.add(cb.like(emp.get("employeeID"), "%" + data.getEmployeeID() + "%"));
        }
        // 员工姓名条件
        if(data.getEmployeeName()!= null && !data.getEmployeeName().equals("")){
            String namePattern = "%" + data.getEmployeeName() + "%";
            if(searchbyOne){
                predicates.add(cb.or(
                    cb.like(emp.get("firstName"), namePattern),
                    cb.like(emp.get("lastName"), namePattern)
                ));
            } else if(searchbyFandL){
                predicates.add(cb.and(
                    cb.like(emp.get("firstName"), namePattern),
                    cb.like(emp.get("lastName"), namePattern)
                ));
            } else if(searchbyCompName){
                predicates.add(cb.like(
                    cb.concat(cb.concat(emp.get("firstName"), " "), emp.get("lastName")),
                    "%" + completeName + "%"
                ));
            }
        }
        // 部门/职位/工作地点条件
        if(data.getDepartmentID()!=0) {
            predicates.add(cb.equal(emp.get("departmentID"), data.getDepartmentID()));
        }
        if(data.getPositionID()!=0) {
            predicates.add(cb.equal(emp.get("positionID"), data.getPositionID()));
        }
        if(data.getWorkplaceID()!=0) {
            predicates.add(cb.equal(emp.get("workplaceID"), data.getWorkplaceID()));
        }
    }

    // 添加WHERE条件(OR连接所有谓词)
    if(!predicates.isEmpty()){
        cq.where(cb.or(predicates.toArray(new Predicate[0])));
    }
    // 排序
    cq.orderBy(cb.desc(emp.get("joinDate")));

    Query<Object[]> q = session.createQuery(cq);
    employees = q.getResultList();
}catch(Exception e){
    e.printStackTrace();
}finally{
    session.close();
}
return employees;

最后提醒

  • 千万不要混用HQL和Criteria API,选一种方式坚持用就好
  • 用字符串拼接HQL时一定要注意空格,避免低级语法错误
  • 优先用Criteria API,它能帮你自动处理语法、避免SQL注入,还能适配不同数据库的语法差异

内容的提问来源于stack exchange,提问作者Snow

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:59:18