如何使用Spring的JDBCTemplate有效执行IN()SQL查询?


177

我想知道是否有使用Spring的JDBCTemplate进行IN()查询的更优雅的方法。目前,我正在执行以下操作:

StringBuilder jobTypeInClauseBuilder = new StringBuilder();
for(int i = 0; i < jobTypes.length; i++) {
    Type jobType = jobTypes[i];

    if(i != 0) {
        jobTypeInClauseBuilder.append(',');
    }

    jobTypeInClauseBuilder.append(jobType.convert());
}

这是很痛苦的,因为如果我只有九行用于为IN()查询构建子句。我想要类似预准备语句的参数替换

Answers:


275

您需要一个参数源:

Set<Integer> ids = ...;

MapSqlParameterSource parameters = new MapSqlParameterSource();
parameters.addValue("ids", ids);

List<Foo> foo = getJdbcTemplate().query("SELECT * FROM foo WHERE a IN (:ids)",
     parameters, getRowMapper());

仅当getJdbcTemplate()返回类型的实例时,此方法才有效NamedParameterJdbcTemplate


5
完美,NamedParameterJdbcTemplate正是我想要的。另外,我更喜欢命名参数,而不是各处的问号。非常感谢!
Malax

5
这适用于小型列表,但尝试在大型列表上使用它会导致查询中::ids替换为“?,?,?,?,?............”并且有足够的列表项溢出。是否有适用于大型列表的解决方案?
nsayer 2010年

您可能应该将值插入到临时表中,并使用来建立条件WHERE NOT EXISTS (SELECT ...)
打哈欠

6
完成答案:Spring 3.1参考—传入IN子句的值列表。但是在Reference中,没有什么可说的:可以传递任何Collection
Timofey Gorshkov

9
奇怪的是,当我尝试此操作时,出现“错误代码[17004];无效的列类型”。
Trevor

61

我像这样用spring jdbc进行“ in子句”查询:

String sql = "SELECT bg.goodsid FROM beiker_goods bg WHERE bg.goodsid IN (:goodsid)";

List ids = Arrays.asList(new Integer[]{12496,12497,12498,12499});
Map<String, List> paramMap = Collections.singletonMap("goodsid", ids);
NamedParameterJdbcTemplate template = 
    new NamedParameterJdbcTemplate(getJdbcTemplate().getDataSource());

List<Long> list = template.queryForList(sql, paramMap, Long.class);

10
您刚刚发布了一个将近三年的问题的答案,答案与接受的答案相同。这背后有什么充分的理由吗?:-)
Malax 2012年

16
该答案更加清晰,因为它说明了该API需要NamedParameterJdbcTemplate ...因此,感谢您提供其他详细信息janwen
IcedD​​ante

@janwen,感谢您的解决方案!!!根据我的要求,它工作正常!
卡西克·阿玛纳特·萨akre

19

如果出现以下情况的异常:无效的列类型

请使用getNamedParameterJdbcTemplate()代替getJdbcTemplate()

 List<Foo> foo = getNamedParameterJdbcTemplate().query("SELECT * FROM foo WHERE a IN (:ids)",parameters,
 getRowMapper());

请注意,后两个参数会交换。


2
这似乎不是这个问题的答案。它应该是对另一个答案的评论吗?
Dave Schweisguth,2014年

2
@DaveSchweisguth两年后,肯定可以得到答案。
dwjohnston 2015年

2

请参考这里

使用命名参数写查询,ListPreparedStatementSetter按顺序对所有参数使用simple 。只需添加以下代码段即可将传统形式的查询转换为可用参数,

ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(namedSql);

List<Integer> parameters = new ArrayList<Integer>();
for (A a : paramBeans)
    parameters.add(a.getId());

MapSqlParameterSource parameterSource = new MapSqlParameterSource();
parameterSource.addValue("placeholder1", parameters);
// create SQL with ?'s
String sql = NamedParameterUtils.substituteNamedParameters(parsedSql, parameterSource);     
return sql;

对我来说,这是唯一可行的答案,因为我只想设置几个占位符
Kapil

-4

自2009年以来,许多事情发生了变化,但是我只能找到答案,指出您需要使用NamedParametersJDBCTemplate。

对我来说,如果我只是做一个

db.query(sql, new MyRowMapper(), StringUtils.join(listeParamsForInClause, ","));

使用SimpleJDBCTemplate或JDBCTemplate


11
该解决方案的问题在于,其中的内容listeParamsForInClause不会被转义,并使您容易受到SQL注入的攻击。
Malax
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.