JbdcTemplate - 带有动态 SQL 查询的 PreparedStatements [英] JbdcTemplate - PreparedStatements with Dynamic SQL Query

查看:34
本文介绍了JbdcTemplate - 带有动态 SQL 查询的 PreparedStatements的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道 jdbcTemplate 可以用来创建 PreparedStatements 如果你设置它这样做:

私有 JdbcTemplate jdbcTemplate;String sqlQuery = "Select * from table where column = ?";字符串值 = "值";this.jbdcTemplate.query(sqlQuery, new Object[] { value }, rs, rowNum -> {System.out.println(rs.getString("column"));});

但是,我在 Where 子句中有一个包含许多 AND 运算符的查询,并且根据某些条件,可能会或可能不会将特定的 AND 语句添加到查询字符串中.

私有 JdbcTemplate jdbcTemplate;StringBuilder sqlQuery = new StringBuilder("Select * from table where 1=1 ");//基本查询如果(某些条件)sqlQuery.append("And column1 = '" + value1 + "'");如果(某些条件2)sqlQuery.append("And column2 = '" + value2 + "'");如果(某些条件3)sqlQuery.append("And column3 = '" + value3 + "'");//等等...

使用这种类型的动态查询,我无法在编译时确切知道要在 new Object[] {} 字段中放置多少值,因为 someCondition 字段在运行时总是在变化.

有没有办法编写 this.jdbcTemplate.query(sqlQuery.toString(), new Object[] {}... 来适应这些动态 AND 语句?

解决方案

在考虑了@mustaccio 在他对我最初问题的评论中所说的话后,我找到了一个解决方案.我还参与了this stackoverflow question的部分解决方案,并在我自己的解决方案中使用了它.

我遇到的主要问题是在运行时动态创建 Object[] 数组,因为您无法将元素动态添加到 Object[] 数组.它们在初始化时必须具有定义的大小.

首先,我创建一个名为 queryArgs 的字符串数组列表.每当其中一个 if 条件证明为真并且我们在查询中添加 AND 语句时,我还会添加另一行代码,将要插入到preparedStatement 中的值添加到 queryArgs数组列表.完成后,我创建一个新的 Object[] 数组,其大小被初始化为 queryArgs 数组列表的大小.最后,我遍历 Object[] 数组中的每个元素,将它们设置为等于 queryArgs 中的值.

私有 JdbcTemplate jdbcTemplate;列出<查询结果>jdbcQuery(QueryParams queryParams) {/* 基本查询 */StringBuilder sqlQuery = new StringBuilder("Select * from table where 1=1 ");/* 存储动态preparedStatement 参数*/列表<字符串>queryArgs = new ArrayList<>();如果(某些条件){sqlQuery.append("and column1 = ?");queryArgs.add(queryParams.value1);}如果(某些条件2){sqlQuery.append("and column2 = ?");queryArgs.add(queryParams.value2);}如果(某些条件3){sqlQuery.append("And column3 = ?");queryArgs.add(queryParams.value3);}//等等.../* 这是我在上面的 stackoverflow 问题中使用的部分 */对象[]preparedStatementArgs = new Object[queryArgs.size()];for(int i = 0; i 

异常值是上面的动态 AND 语句之一是这样写的:

AND column4 IN ('x','y','z','etc..'‌ )

,括号内的值在运行时也是动态的.我的服务收到一个如下所示的字符串值:

String queryParams.value4 = "x,y,z,etc...";

我不能这样编写preparedStatement:AND column4 IN (?) 然后简单地插入queryParams.value4,因为它会处理queryParams.value4 作为字符串文字,这会导致错误.

为了解决这个问题,我创建了另一个名为 value4Array 的字符串数组列表.我循环遍历 queryParams.value4 中的每个字符,并检查循环中的当前字符是否等于逗号,即我们的分隔符.如果是,那么我创建一个以逗号开头的所有字符的子字符串,并将新创建的字符串添加到 value4Array.

下一步是创建动态 AND column4 IN (?) 语句.我通过遍历我们刚刚创建的 value4Array 数组列表中的每个字符串值,并根据有多少字符串执行 sql.append("?") 来做到这一点value4Array.之后,剩下的逻辑和我上面的解决方案一样.

/* 此函数采用逗号分隔的字符串文字(value4 : "x,y,z,etc...")并将其解析为字符串数组.*/私有列表<字符串>parseValue4(字符串值4){整数值索引= 0;列表<字符串>value4Array = new ArrayList<>();for(int i = 0; i < value4.length(); i++){if(value4.charAt(i) == ','){value4Array.add(value4.substring(valueIndex, i));值索引 = i + 1;}否则 if(i == value4.length() - 1){value4Array.add(value4.substring(valueIndex, value4.length()));}}返回值4数组;}如果(某些条件4){列表<字符串>value4Array = parseValue4(queryParams.value4);sqlQuery.append("And column4 IN (");/* 基础 AND 语句 */for(int i = 0; i < value4Array.size(); i++){if(i == value4Array.size() - 1)sqlQuery.append("?)");else/* 动态附加 ? 的 */sqlQuery.append("?,");queryArgs.add(value4Array.get(i));}}

I know jdbcTemplate can be used to create PreparedStatements if you set it up to do so:

i.e.

private JdbcTemplate jdbcTemplate;
String sqlQuery = "Select * from table where column = ?";
String value = "value";
this.jbdcTemplate.query(sqlQuery, new Object[] { value }, rs, rowNum -> {
  System.out.println(rs.getString("column"));
});

However, I have a query with many AND operators in the Where clause, and depending on some condition, a specific AND statement may or may not be added to the query string.

i.e.

private JdbcTemplate jdbcTemplate;
StringBuilder sqlQuery = new StringBuilder("Select * from table where 1=1 "); //base query
if(someCondition)
   sqlQuery.append("And column1 = '" + value1 + "'");
if(someCondition2)
   sqlQuery.append("And column2 = '" + value2 + "'");
if(someCondition3)
   sqlQuery.append("And column3 = '" + value3 + "'");
//etc...

With this type of dynamic query, I am unable to know exactly how many values to place in the new Object[] {} field at compile time, because the someCondition fields are always changing at runtime.

Is there a way to write the this.jdbcTemplate.query(sqlQuery.toString(), new Object[] {}... to accommodate these dynamic AND statements?

解决方案

I found a solution after taking into consideration what @mustaccio said in his comment to my original question. I also took part of the solution from this stackoverflow question and used it in my own solution.

The main issue I was having was dynamically creating an Object[] array at runtime, since you can't dynamically add elements to an Object[] array. They must have a defined size when initialized.

First, I create an arraylist of strings called queryArgs. Every time one of the if conditions proves true and we add an AND statement to the query, I also add another line of code that adds the value to be plugged in the preparedStatement to the queryArgs arraylist. Once that's done, I create a new Object[] array whose size is initialized to the size of the queryArgs arraylist. Lastly, I loop through each element in the Object[] array, setting them equal to the values in queryArgs.

private JdbcTemplate jdbcTemplate;

List<QueryResults> jdbcQuery(QueryParams queryParams) {
    /* base query */
    StringBuilder sqlQuery = new StringBuilder("Select * from table where 1=1 ");
    /* stores the dynamic preparedStatement arguments */
    List<String> queryArgs = new ArrayList<>();

    if(someCondition){
       sqlQuery.append("And column1 = ? ");
       queryArgs.add(queryParams.value1);
    }
    if(someCondition2){
       sqlQuery.append("And column2 = ? ");
       queryArgs.add(queryParams.value2);
    }
    if(someCondition3){
       sqlQuery.append("And column3 = ? ");
        queryArgs.add(queryParams.value3);
    }
    //etc...

    /* this is the part I used from the above stackoverflow question */
    Object[] preparedStatementArgs = new Object[queryArgs.size()];
    for(int i = 0; i < preparedStatementArgs.length; i++){
        preparedStatementArgs[i] = queryArgs.get(i);
    }

    /* Lastly, execute the query */
    return this.jdbcTemplate.query(sqlQuery.toString(),
    preparedStatementArgs, (rs, rowNum) -> {

        QueryResults result = new QueryResults();
        /* store the results of the query... */
    });
}

The outlier is that one of the dynamic AND statements above is written like this:

AND column4 IN ('x','y','z','etc..'‌​)

, where the values inside of the parentheses are also dynamic at runtime. My service receives a string value that looks like this:

String queryParams.value4 = "x,y,z,etc...";

I can't write the preparedStatement like this: AND column4 IN (?) and then simply plug in queryParams.value4 because it will treat queryParams.value4 as a string literal, which leads to errors.

To solve this issue, I create another arraylist of strings called value4Array. I loop through every character in queryParams.value4, and I check if the current character in the loop is equal to a comma, our delimiter. If it is, then I create a substring of all the characters leading up to that comma, and add that newly created string to value4Array.

The next step is to create the dynamic AND column4 IN (?) statement. I do this by looping through each string value in the value4Array arraylist we just created, and doing a sql.append("?"), based on how many strings are in value4Array. After this, the rest of the logic is the same as my solution above.

/* this function takes the comma delimited string literal (value4 : "x,y,z,etc...")
   and parses it into an array of strings. */
private List<String> parseValue4(String value4){
    int valueIndex= 0;
    List<String> value4Array = new ArrayList<>();
    for(int i = 0; i < value4.length(); i++){
        if(value4.charAt(i) == ','){
            value4Array.add(value4.substring(valueIndex, i));
            valueIndex = i + 1;
        }
        else if(i == value4.length() - 1){
            value4Array.add(value4.substring(valueIndex, value4.length()));
        }
    }
    return value4Array;
}
if(someCondition4){
   List<String> value4Array = parseValue4(queryParams.value4);
   sqlQuery.append("And column4 IN ("); /* base AND statement */
    for(int i = 0; i < value4Array.size(); i++){
        if(i == value4Array.size() - 1)
            sqlQuery.append("?)");
        else                       /* dynamically appending ?'s */
            sqlQuery.append("?,");
        queryArgs.add(value4Array.get(i));
    }
}

这篇关于JbdcTemplate - 带有动态 SQL 查询的 PreparedStatements的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆