在java.sql实例中使用SQL IN子句的最佳变通方法是什么?由于SQL注入攻击安全问题,不支持多值的PreparedStatement:一个?占位符表示一个值,而不是一个值列表。

考虑下面的SQL语句:

SELECT my_column FROM my_table where search_column IN (?)

使用preparedStatement。setString(1, "'A', 'B', 'C'");本质上是一种无用的尝试,试图解决使用原因?首先。

有什么可行的解决办法?


当前回答

使用嵌套查询是一种令人不快的变通方法,但肯定是可行的。创建一个包含列的临时表MYVALUES。将值列表插入到MYVALUES表中。然后执行

select my_column from my_table where search_column in ( SELECT value FROM MYVALUES )

很丑,但如果你的价值列表非常大,这是一个可行的选择。

如果您的数据库没有缓存准备好的语句,这种技术还有一个额外的好处,那就是可能会从优化器获得更好的查询计划(检查一个页面是否有多个值,表只能检查一次,而不是每个值检查一次,等等),这样可以节省开销。您的“insert”将需要批处理,并且可能需要调整MYVALUES表以使锁定或其他高开销保护最小化。

其他回答

似乎还没有人建议使用现成的查询构建器,比如jOOQ或QueryDSL,甚至Criteria query,它们可以开箱即用地管理动态IN列表,可能包括对可能出现的所有边缘情况的管理,例如:

运行到Oracle的每个IN列表最多1000个元素(与绑定值的数量无关) 遇到任何驱动程序的绑定值的最大数目,这是我在这个答案中记录的 遇到游标缓存争用问题,因为太多不同的SQL字符串被“硬解析”,执行计划不能再缓存了(jOOQ和最近Hibernate也通过提供IN列表填充来解决这个问题)

(免责声明:我为jOOQ背后的公司工作)

我的解决方案(JavaScript)

    var s1 = " SELECT "

 + "FROM   table t "

 + "  where t.field in ";

  var s3 = '(';

  for(var i =0;i<searchTerms.length;i++)
  {
    if(i+1 == searchTerms.length)
    {
     s3  = s3+'?)';
    }
    else
    {
        s3  = s3+'?, ' ;
    }
   }
    var query = s1+s3;

    var pstmt = connection.prepareStatement(query);

     for(var i =0;i<searchTerms.length;i++)
    {
        pstmt.setString(i+1, searchTerms[i]);
    }

SearchTerms是包含你的输入/键/字段等的数组

你可以使用PreparedStatement的setArray()方法

PreparedStatement statement = connection.prepareStatement("Select * from emp where field in (?)");
statement.setArray(1, Arrays.asList(1,2,3,4,5));
ResultSet rs = statement.executeQuery();

我遇到了一些与准备好的语句相关的限制:

The prepared statements are cached only inside the same session (Postgres), so it will really work only with connection pooling A lot of different prepared statements as proposed by @BalusC may cause the cache to overfill and previously cached statements will be dropped The query has to be optimized and use indices. Sounds obvious, however e.g. the ANY(ARRAY...) statement proposed by @Boris in one of the top answers cannot use indices and query will be slow despite caching The prepared statement caches the query plan as well and the actual values of any parameters specified in the statement are unavailable.

在建议的解决方案中,我会选择一个不会降低查询性能并且查询次数较少的解决方案。这将是#4(批处理少数查询)从@Don链接或指定NULL值为不需要的'?@Vladimir Dyuzhev提出的标记

我认为您可以(使用基本的字符串操作)在PreparedStatement中生成查询字符串,使其具有与列表中项的数量相匹配的若干?

当然,如果你这样做,你只是一个步骤,生成一个巨大的链或在你的查询,但没有正确的数字?在查询字符串中,我不知道你还能如何解决这个问题。