JbdcTemplate - 带有动态 SQL 查询的 PreparedStatements
JbdcTemplate - PreparedStatements with Dynamic SQL Query
我知道 jdbcTemplate
可以用来创建 PreparedStatements
如果你这样设置的话:
即
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"));
});
但是,我有一个在 Where 子句中包含许多 AND 运算符的查询,并且根据某些条件,可能会或可能不会将特定的 AND 语句添加到查询字符串中。
即
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...
使用这种类型的动态查询,我无法确切知道在编译时要在 new Object[] {}
字段中放置多少个值,因为 someCondition
字段在运行时总是在变化。
有没有办法编写 this.jdbcTemplate.query(sqlQuery.toString(), new Object[] {}...
来适应这些动态 AND 语句?
在考虑了@mustaccio 在他对我的原始问题的评论中所说的内容后,我找到了解决方案。我还从 this Whosebug question 中获取了部分解决方案,并将其用于我自己的解决方案中。
我遇到的主要问题是在运行时动态创建一个 Object[]
数组,因为您不能动态地将元素添加到 Object[]
数组。它们在初始化时必须具有定义的大小。
首先,我创建了一个名为 queryArgs
的字符串数组列表。每次 if 条件之一证明为真并且我们向查询添加 AND
语句时,我还添加了另一行代码,将要插入 preparedStatement 的值添加到 queryArgs
arraylist。完成后,我创建了一个新的 Object[]
数组,其大小被初始化为 queryArgs
数组列表的大小。最后,我遍历 Object[]
数组中的每个元素,将它们设置为等于 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 Whosebug 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... */
});
}
离群点是上面的动态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
数组列表中的每个字符串值,并根据 value4Array
中的字符串数量执行 sql.append("?")
。在此之后,其余的逻辑与我上面的解决方案相同。
/* 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));
}
}
您正在获取字符串类型 (List<String> queryArgs = new ArrayList<>();)
的列表。
如果参数是整数类型怎么办?有没有办法存储多种类型的数据?
我知道 jdbcTemplate
可以用来创建 PreparedStatements
如果你这样设置的话:
即
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"));
});
但是,我有一个在 Where 子句中包含许多 AND 运算符的查询,并且根据某些条件,可能会或可能不会将特定的 AND 语句添加到查询字符串中。
即
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...
使用这种类型的动态查询,我无法确切知道在编译时要在 new Object[] {}
字段中放置多少个值,因为 someCondition
字段在运行时总是在变化。
有没有办法编写 this.jdbcTemplate.query(sqlQuery.toString(), new Object[] {}...
来适应这些动态 AND 语句?
在考虑了@mustaccio 在他对我的原始问题的评论中所说的内容后,我找到了解决方案。我还从 this Whosebug question 中获取了部分解决方案,并将其用于我自己的解决方案中。
我遇到的主要问题是在运行时动态创建一个 Object[]
数组,因为您不能动态地将元素添加到 Object[]
数组。它们在初始化时必须具有定义的大小。
首先,我创建了一个名为 queryArgs
的字符串数组列表。每次 if 条件之一证明为真并且我们向查询添加 AND
语句时,我还添加了另一行代码,将要插入 preparedStatement 的值添加到 queryArgs
arraylist。完成后,我创建了一个新的 Object[]
数组,其大小被初始化为 queryArgs
数组列表的大小。最后,我遍历 Object[]
数组中的每个元素,将它们设置为等于 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 Whosebug 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... */
});
}
离群点是上面的动态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
数组列表中的每个字符串值,并根据 value4Array
中的字符串数量执行 sql.append("?")
。在此之后,其余的逻辑与我上面的解决方案相同。
/* 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));
}
}
您正在获取字符串类型 (List<String> queryArgs = new ArrayList<>();)
的列表。
如果参数是整数类型怎么办?有没有办法存储多种类型的数据?