2013-05-08 48 views
8

使用JPA Criteria API时,直接使用ParameterExpression优于变量的优点是什么?例如。当我想的名字在一个字符串变量来搜索一个客户,我可以写类似使用参数表达式与JPA标准API中的变量API

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(); 
} 

使用参数变为:

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(); 
} 

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

+0

在一般我不能JPA说话,但是我发现OpenJPA在内部将Criteria查询转换为JPQL,并且可以使用OpenJPA特定的功能打印(请参阅htt号码://openjpa.apache.org/builds/2.1.1/apache-openjpa/docs/ch13s03.html)。 第一个查询转换为“SELECT c FROM Customer c WHERE c.name ='test Customer'”。这意味着它不使用参数,所以如果这进一步转换为SQL,相应的准备语句将不使用参数。第二个版本转换为JPQL“SELECT c FROM Customer c WHERE c.name =:name”,所以我将使用参数。 – 2013-05-08 11:48:31

+0

经过一些更多的测试后,我发现用JPQL编写相同的查询并使用名称“'或'x'='x”注入JPQL。使用标准API时,生成的OpenJPA日志JPQL看起来完全相同。然而,OpenJPA记录的实际SQL使用准备好的语句,在JPQL的情况下,参数值为“'或'x'='x”,而不是''。这意味着SQL注入在这里不起作用!不幸的是,我不知道这是多么可靠。这似乎是一个无证的功能。 – 2013-05-10 10:58:20

+0

提示:我只是给了http://www.querydsl.com/一个尝试,它的语法更加简洁和可读。它似乎通过默认使用参数防止SQL注入。 – 2013-05-10 12:39:01

回答

0

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

SQL注入总是由开发人员决定,他们是否验证某些正在用作参数的用户输入。

+0

这是一件很好的事情要知道。我更喜欢简单的代码以上优化的代码,直到它被确定为一个问题。我在where子句中使用可选条件的参数时遇到的问题是,您需要重复代码,如“if(optionalParameter!= null)”来声明和设置参数。 你的第二个答案让我困惑。我一直认为(尽可能实现bug)参数保证不会遭受SQL注入攻击,我想知道我的更简单的第一种方法是否会受到SQL注入的影响。顺便说一句,我正在使用OpenJPA。 – 2013-05-08 11:22:48

0

可以使用ParameterExpression这样的: 假设你有一些输入滤波器,一个例子可以是这样的:在您的查询

  • 你必须检查的财政规则的价值。

让我们开始: 首先创造CriteriaQuery中和criteriaBuilder和根

 CriteriaBuilder cb = _em.getCriteriaBuilder(); 
     CriteriaQuery<Tuple> cq = cb.createTupleQuery(); 
     Root<RootEntity> soggettoRoot = cq.from(RootEntity.class); 

1) inizialize一个predicateList(用于WHERE子句)和paramList(用于PARAM)

Map<ParameterExpression,String> paramList = new HashMap(); 
List<Predicate> predicateList = new ArrayList<>(); 

)检查输入是否为n ULL和创建predicateList和param

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()()); 
     } 

)创建where子句

cq.where(cb.and(predicateList.toArray(new Predicate[predicateList.size()]))); 
TypedQuery<Tuple> q = _em.createQuery(cq); 

)组PARAM值

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

如果不使用参数,SQL注入是可能的吗? – Alex78191 2018-01-22 23:43:05

+0

是的,这将是可能的 – 2018-01-23 20:05:50