如何使用 Spring 的 JDBCTemplate 有效地执行 IN() SQL 查询?
Posted
技术标签:
【中文标题】如何使用 Spring 的 JDBCTemplate 有效地执行 IN() SQL 查询?【英文标题】:How to execute IN() SQL queries with Spring's JDBCTemplate effectively? 【发布时间】:2009-08-25 09:16:57 【问题描述】:我想知道是否有更优雅的方式来使用 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() 查询的子句。我想要类似准备好的语句的参数替换
【问题讨论】:
【参考方案1】:你想要一个参数来源:
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
类型的实例
【讨论】:
完美,NamedParameterJdbcTemplate 正是我想要的。此外,我更喜欢命名参数,而不是到处都是问号。非常感谢! 这适用于小列表,但尝试在大列表上使用它会导致查询中 :ids 被替换为 "?,?,?,?,?......"并且有足够的列表项它会溢出。是否有适用于大型列表的解决方案? 您可能应该将值插入临时表并使用WHERE NOT EXISTS (SELECT ...)
构建条件。
完整回答:Spring 3.1 Reference — Passing in lists of values for IN clause。但在 Reference 中什么也没说:it is possible to pass any Collection.
奇怪,当我尝试这个时,我得到“错误代码 [17004];无效的列类型”。【参考方案2】:
我使用 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);
【讨论】:
您刚刚发布了一个已存在近三年的问题的答案,其解决方案与已接受的答案相同。这背后有什么好的理由吗? :-) 这个答案提供了更多的清晰度,因为它说明了这个 API 需要 NamedParameterJdbcTemplate ...所以感谢 janwen 提供的额外细节 @janwen ,感谢您的解决方案!!!根据我的要求,它工作正常!!【参考方案3】:如果您遇到异常:无效的列类型
请使用getNamedParameterJdbcTemplate()
而不是getJdbcTemplate()
List<Foo> foo = getNamedParameterJdbcTemplate().query("SELECT * FROM foo WHERE a IN (:ids)",parameters,
getRowMapper());
请注意,后两个参数是交换的。
【讨论】:
这似乎不是这个问题的答案。它应该是对另一个答案的评论吗? @DaveSchweisguth 两年后,它绝对值得回答。 getNamedParameterJdbcTemplate() 未定义。如果需要该方法,需要扩展 NamedParameterJdbcDaoSupport。【参考方案4】:参考here
使用命名参数编写查询,按顺序使用简单的ListPreparedStatementSetter
和所有参数。只需在sn-p下方添加,即可将传统形式的查询转换为可用参数,
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;
【讨论】:
对我来说这是唯一可行的答案,因为我只想设置几个占位符【参考方案5】:自 2009 年以来发生了很多变化,但我只能找到需要使用 NamedParametersJDBCTemplate 的答案。
对我来说,只要我做一个就可以了
db.query(sql, new MyRowMapper(), StringUtils.join(listeParamsForInClause, ","));
使用 SimpleJDBCTemplate 或 JDBCTemplate
【讨论】:
这个解决方案的问题是,listeParamsForInClause
中的内容不会被转义,让你容易受到 SQL 注入的攻击。
以上是关于如何使用 Spring 的 JDBCTemplate 有效地执行 IN() SQL 查询?的主要内容,如果未能解决你的问题,请参考以下文章
阶段3 2.Spring_10.Spring中事务控制_7 spring基于注解的声明式事务控制