Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/api/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在JPA标准API中使用ParameterExpression与变量_Java_Api_Jpa_Criteria - Fatal编程技术网

Java 在JPA标准API中使用ParameterExpression与变量

Java 在JPA标准API中使用ParameterExpression与变量,java,api,jpa,criteria,Java,Api,Jpa,Criteria,使用JPA Criteria API时,直接在变量上使用ParameterExpression有什么好处?例如,当我希望在字符串变量中按名称搜索客户时,我可以编写如下代码 private List<Customer> findCustomer(String name) { CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<Customer> criteriaQuery = cb.crea

使用JPA Criteria API时,直接在变量上使用ParameterExpression有什么好处?例如,当我希望在字符串变量中按名称搜索客户时,我可以编写如下代码

private List<Customer> findCustomer(String name) {
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<Customer> criteriaQuery = cb.createQuery(Customer.class);
    Root<Customer> customer = criteriaQuery.from(Customer.class);
    criteriaQuery.select(customer).where(cb.equal(customer.get("name"), name));
    return em.createQuery(criteriaQuery).getResultList();
}
私有列表findCustomer(字符串名称){
CriteriaBuilder cb=em.getCriteriaBuilder();
CriteriaQuery-CriteriaQuery=cb.createQuery(Customer.class);
Root customer=criteriaQuery.from(customer.class);
criteriaQuery.select(customer).where(cb.equal(customer.get(“name”)),name));
返回em.createQuery(criteriaQuery).getResultList();
}
对于参数,这将成为:

private List<Customer> findCustomerWithParam(String name) {
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<Customer> criteriaQuery = cb.createQuery(Customer.class);
    Root<Customer> customer = criteriaQuery.from(Customer.class);
    ParameterExpression<String> nameParameter = cb.parameter(String.class, "name");
    criteriaQuery.select(customer).where(cb.equal(customer.get("name"), nameParameter));
    return em.createQuery(criteriaQuery).setParameter("name", name).getResultList();
}
private List findCustomerWithParam(字符串名称){
CriteriaBuilder cb=em.getCriteriaBuilder();
CriteriaQuery-CriteriaQuery=cb.createQuery(Customer.class);
Root customer=criteriaQuery.from(customer.class);
ParameterExpression-nameParameter=cb.parameter(String.class,“name”);
criteriaQuery.select(customer).where(cb.equal(customer.get(“name”)、nameparmeter));
返回em.createQuery(criteriaQuery).setParameter(“name”,name).getResultList();
}

为了简洁起见,我更喜欢第一种方法,尤其是当查询使用可选参数变得更长时。使用像SQL注入这样的参数有什么缺点吗?

当使用参数时,很可能(取决于JPA实现、正在使用的数据存储和JDBC驱动程序),SQL将被优化为JDBC参数,因此如果使用不同的参数值执行相同的操作,它将使用相同的JDBC语句


SQL注入始终取决于开发人员是否验证用作参数的某些用户输入。

您可以使用如下参数表达式: 假设您有一些输入过滤器,例如:

  • 在查询中,必须检查会计代码的值
让我们开始: 首先创建criteriaQuery、criteriaBuilder和root

        CriteriaBuilder cb = _em.getCriteriaBuilder();
        CriteriaQuery<Tuple> cq = cb.createTupleQuery();
        Root<RootEntity> soggettoRoot = cq.from(RootEntity.class);
CriteriaBuilder cb=_em.getCriteriaBuilder();
CriteriaQuery cq=cb.createTupleQuery();
Root-soggettoRoot=cq.from(RootEntity.class);
1)将谓词列表(用于where子句)和参数列表(用于param)序列化

Map paramList=newhashmap();
列表谓词列表=新的ArrayList();
2)检查输入是否为空,并创建谓词列表和参数

if( input.getFilterCF() != null){
            //create ParameterExpression
            ParameterExpression<String> cf = cb.parameter(String.class);


           //if like clause
            predicateList.add(cb.like(root.<String>get("cf"), cf));
            paramList.put(cf , input.getFilterCF() + "%");

           //if equals clause
           //predicateList.add(cb.equal(root.get("cf"), cf));   
           //paramList.put(cf,input.getFilterCF()());
        }
if(input.getFilterCF()!=null){
//创建参数表达式
ParameterExpression cf=cb.parameter(String.class);
//if-like条款
add(cb.like(root.get(“cf”),cf));
paramList.put(cf,input.getFilterCF()+“%”;
//如果等于子句
//add(cb.equal(root.get(“cf”),cf));
//put(cf,input.getFilterCF());
}
3)创建where子句

 cq.where(cb.and(predicateList.toArray(new   Predicate[predicateList.size()])));
TypedQuery<Tuple> q = _em.createQuery(cq);
cq.where(cb.and(predicateList.toArray)(新谓词[predicateList.size()));
TypedQuery q=_em.createQuery(cq);
4)设置参数值

        for(Map.Entry<ParameterExpression,String> entry : paramList.entrySet())
        {
            q.setParameter(entry.getKey(), entry.getValue());
        }
for(Map.Entry:paramList.entrySet())
{
q、 setParameter(entry.getKey(),entry.getValue());
}

在第二种情况下,您不必要地使用了ParameterExpression。 CriteriaQuery的where()方法接受谓词作为其参数

与此相反:

ParameterExpression<String> nameParameter = cb.parameter(String.class, "name");
criteriaQuery.select(customer).where(cb.equal(customer.get("name"), nameParameter));
return em.createQuery(criteriaQuery).setParameter("name", name).getResultList();
ParameterExpression能够通过其in()、isNull()和isNotNull()方法为您生成谓词,请参阅。在我看来,这将是它的主要优势


注意:可以像您那样使用ParameterExpression,这相当于将命名参数传递给JPQL查询。

这是一件好事。我更喜欢简单的代码,而不是优化的代码,直到它被确定为一个问题。我在where子句中使用可选条件的参数时遇到的问题是,您需要使用类似“if(optionalParameter!=null)”的重复代码来声明和设置参数。你的第二个答案把我弄糊涂了。我一直认为(直到可能的实现错误)参数保证不会受到SQL注入攻击,我想知道我的简单的第一种方法是否会受到SQL注入的影响。顺便说一句,我使用的是OpenJPA。一般来说,我不能代表JPA,但我发现OpenJPA在内部将一个条件查询转换为JPQL,这可以通过使用OpenJPA特定的功能打印出来(请参阅)。第一个查询转换为“从客户c中选择c,其中c.name=‘测试客户’”。这意味着它不使用参数,因此如果进一步将其转换为SQL,则相应的准备语句将不使用参数。第二个版本转换为JPQL“从客户c中选择c,其中c.name=:name”,因此我将使用参数。经过更多测试,我发现使用JPQL编写相同的查询并使用name“'或'x'='x”注入JPQL。使用CriteriaAPI时,OpenJPA记录的生成JPQL看起来完全相同。然而,OpenJPA记录的实际SQL随后使用一个准备好的语句,该语句的参数值为“'或'x'='x”,而不是JPQL中的“”。这意味着SQL注入在这里不起作用!不幸的是,我不知道这有多可靠。提示:我只是尝试了一下,它的语法更加简洁易读。默认情况下使用参数似乎可以防止sql注入。也就是说,如果不使用参数,sql注入是可能的?如果不使用参数,sql注入是否可能?
ParameterExpression<String> nameParameter = cb.parameter(String.class, "name");
criteriaQuery.select(customer).where(cb.equal(customer.get("name"), nameParameter));
return em.createQuery(criteriaQuery).setParameter("name", name).getResultList();
Predicate predicate = cb.equal(customer.get("name"), name);
criteriaQuery.select(customer).where(predicate);
return em.createQuery(criteriaQuery).getResultList();