【问题标题】:How to execute IN() SQL queries with Spring's JDBCTemplate effectively?如何使用 Spring 的 JDBCTemplate 有效地执行 IN() SQL 查询?
【发布时间】: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() 查询的子句。我想要类似准备好的语句的参数替换

【问题讨论】:

    标签: java sql spring jdbc jdbctemplate


    【解决方案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 ...) 构建条件。
    • 奇怪,当我尝试这个时,我得到“错误代码 [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 注入的攻击。
    猜你喜欢
    • 2010-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-04
    • 2018-06-02
    • 1970-01-01
    • 2017-04-16
    • 2021-12-23
    相关资源
    最近更新 更多