Hibernate:org.hibernate.QueryParameterException:无法找到命名参数

时间:2015-05-12 14:30:25

标签: java spring hibernate spring-mvc

我正在开发一个Spring-MVC应用程序,我希望同时在多个变量上运行搜索。但是代码仍然无法为第一个值本身设置参数。我不知道为什么。你能帮忙的话,我会很高兴。

ListStudents:

@Override
public List<Student> addHostSearchHistory(HostSearchHistory hostSearchHistory, Long hostId) {
    session = this.sessionFactory.getCurrentSession();
    Host host = (Host) session.get(Host.class,hostId);
    host.getHostSearchHistorySet().add(hostSearchHistory);
    hostSearchHistory.setHsHistory(host);
    session.save(hostSearchHistory);
    session.flush();

    StringBuilder sb = new StringBuilder();
    sb.append("from Student as s where ");

    if(!(hostSearchHistory.getCountry()==null)){
        sb.append("s.studentCountry=:").append(hostSearchHistory.getCountry());
    }
    if(!(hostSearchHistory.getCity()==null)){
        sb.append(" OR s.city=:").append(hostSearchHistory.getCity());
    }
    if(!(hostSearchHistory.getDrivingLicense()==null)){
        sb.append(" OR s.studentInfoDetails.drivingLicense=").append(hostSearchHistory.getDrivingLicense());
    }
    if(!(hostSearchHistory.getGender()==null)){
        sb.append(" OR s.gender=").append(hostSearchHistory.getGender());
    }
    if(!(hostSearchHistory.getMotherTongue()==null)){
        sb.append(" OR s.studentInfoDetails.motherTongue=:").append(hostSearchHistory.getMotherTongue());
    }
    if(!(hostSearchHistory.getSmoker()==null)){
        sb.append(" OR s.studentInfoDetails.smoker=").append(hostSearchHistory.getSmoker());
    }
    if(!(hostSearchHistory.getPreviousAuPair()==null)){
        sb.append(" OR s.studentInfoDetails.previouslyAuPair=").append(hostSearchHistory.getPreviousAuPair());
    }
    if(!(hostSearchHistory.getWillingToWork()==null)){
        sb.append(" OR s.studentInfoDetails.willingToWork=").append(hostSearchHistory.getWillingToWork());
    }
    if(!(hostSearchHistory.getWorkForSingleParent()==null)){
        sb.append(" OR s.studentInfoDetails.workForSingleParent=").append(hostSearchHistory.getWorkForSingleParent());
    }
    if(!(hostSearchHistory.getWorkingForDisabledChild()==null)){
        sb.append(" OR s.studentInfoDetails.workingForDisabledChild=").append(hostSearchHistory.getWorkingForDisabledChild());
    }
    if(!(hostSearchHistory.getOtherLanguages()==null)){
        sb.append(" OR s.studentInfoDetails.otherLanguages=:").append(hostSearchHistory.getOtherLanguages());
    }

    sb.append(" order by s.registrationDate desc");

    System.out.println("Sb.toString is "+sb.toString());

    Query query = session.createQuery(sb.toString());

// The code fails here
    if(!(hostSearchHistory.getCountry()==null)){
        query.setParameter("studentCountry",hostSearchHistory.getCountry());
    }
    if(!(hostSearchHistory.getCity()==null)){
        query.setParameter("city",hostSearchHistory.getCity());
    }
    if(!(hostSearchHistory.getDrivingLicense()==null)){
        query.setParameter("drivingLicense",hostSearchHistory.getDrivingLicense());
    }
    if(!(hostSearchHistory.getGender()==null)){
        query.setParameter("gender",hostSearchHistory.getGender());
    }
    if(!(hostSearchHistory.getMotherTongue()==null)){
        query.setParameter("motherTongue",hostSearchHistory.getMotherTongue());
    }
    if(!(hostSearchHistory.getSmoker()==null)){
        query.setParameter("smoker",hostSearchHistory.getSmoker());
    }
    if(!(hostSearchHistory.getPreviousAuPair()==null)){
        query.setParameter("previouslyAuPair",hostSearchHistory.getPreviousAuPair());
    }
    if(!(hostSearchHistory.getWillingToWork()==null)){
        query.setParameter("willingToWork",hostSearchHistory.getWillingToWork());
    }
    if(!(hostSearchHistory.getWorkForSingleParent()==null)){
        query.setParameter("workForSingleParent",hostSearchHistory.getWorkForSingleParent());
    }
    if(!(hostSearchHistory.getWorkingForDisabledChild()==null)){
        query.setParameter("workingForDisabledChild",hostSearchHistory.getWorkingForDisabledChild());
    }
    if(!(hostSearchHistory.getOtherLanguages()==null)){
        query.setParameter("otherLanguages",hostSearchHistory.getOtherLanguages());
    }

    List<Student> studentList = query.list();
    for(Student student : studentList){
        System.out.println("Student name is "+student.getUsername());
    }
   return studentList;

}

输出sb.toString():

Sb.toString is from Student as s where s.studentCountry=:Germany OR s.city=:Hamburg OR s.studentInfoDetails.drivingLicense=true OR s.gender=male OR s.studentInfoDetails.smoker=true OR s.studentInfoDetails.willingToWork=true OR s.studentInfoDetails.workingForDisabledChild=true order by s.registrationDate desc

错误日志:

org.hibernate.QueryParameterException: could not locate named parameter [studentCountry]
    org.hibernate.engine.query.spi.ParameterMetadata.getNamedParameterDescriptor(ParameterMetadata.java:148)
    org.hibernate.engine.query.spi.ParameterMetadata.getNamedParameterExpectedType(ParameterMetadata.java:165)
    org.hibernate.internal.AbstractQueryImpl.determineType(AbstractQueryImpl.java:523)
    org.hibernate.internal.AbstractQueryImpl.setParameter(AbstractQueryImpl.java:493)
    com.journaldev.spring.dao.HostSearchHistoryDAOImpl.addHostSearchHistory(HostSearchHistoryDAOImpl.java:82)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

我做错了什么。你能帮忙的话,我会很高兴。非常感谢。 : - )

2 个答案:

答案 0 :(得分:1)

您应该使用Predrag建议的第一个选项。使用第二个选项有两个主要缺点:

1)性能低下。数据库不会使用绑定变量缓存一个预准备语句,但其中许多语句适用于所有输入参数组合。这意味着重新解析语句并从缓存中清除其他准备好的语句。

2)安全。没有绑定变量的语句非常容易受到SQL注入攻击。在您的具体示例中可能会或可能不是这种情况,但通常,假设恶意用户(黑客:))为城市或其他字段输入以下或类似的过滤条件:

' union select null, USERNAME || ',' || PASSWORD, null, null... from USER_PASSWORDS --

他会将所有用户名/密码作为学生城市返回。 :) 当然,这只是一个通用示例,它可能是数据库中实际存在的表中的其他查询部分或其他敏感数据。

答案 1 :(得分:0)

简短的回答 - 你写了这个

query.setParameter("studentCountry",hostSearchHistory.getCountry());

但在您的sb.toString()输出中,您没有:studentCountry

方法的整个第一部分应该有硬编码的参数名称,如sb.append("s.studentCountry=:studentCountry"),然后第二部分应该有用。

或者,使用sb.append("s.studentCountry='").append(hostSearchHistory.getCountry()).append("'");并且根本不使用参数。