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

考虑下面的SQL语句:

SELECT my_column FROM my_table where search_column IN (?)

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

有什么可行的解决办法?


当前回答

尝试使用instr函数?

select my_column from my_table where  instr(?, ','||search_column||',') > 0

then

ps.setString(1, ",A,B,C,"); 

不可否认,这是一个肮脏的黑客,但它确实减少了sql注入的机会。在甲骨文工作。

其他回答

而不是使用

SELECT my_column FROM my_table where search_column IN (?)

使用Sql语句作为

select id, name from users where id in (?, ?, ?)

and

preparedStatement.setString( 1, 'A');
preparedStatement.setString( 2,'B');
preparedStatement.setString( 3, 'C');

或者使用存储过程,这将是最好的解决方案,因为sql语句将被编译并存储在数据库服务器中

尝试使用instr函数?

select my_column from my_table where  instr(?, ','||search_column||',') > 0

then

ps.setString(1, ",A,B,C,"); 

不可否认,这是一个肮脏的黑客,但它确实减少了sql注入的机会。在甲骨文工作。

我的解决方案(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是包含你的输入/键/字段等的数组

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

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

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

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

在研究了不同论坛上的各种解决方案后,没有找到一个好的解决方案,我觉得下面的方法是最容易遵循和编码的:

示例:假设您有多个参数要传递到' in '子句中。只要在'IN'子句中放入一个虚拟字符串,例如,“PARAM”确实表示将在这个虚拟字符串中出现的参数列表。

    select * from TABLE_A where ATTR IN (PARAM);

您可以在Java代码中将所有参数收集到一个String变量中。可以这样做:

    String param1 = "X";
    String param2 = "Y";
    String param1 = param1.append(",").append(param2);

你可以将所有用逗号分隔的参数附加到一个String变量中,在我们的例子中是'param1'。

在将所有参数收集到单个字符串中之后,您可以将查询中的虚拟文本替换为参数String,即param1,在本例中为“PARAM”。以下是你需要做的:

    String query = query.replaceFirst("PARAM",param1); where we have the value of query as 

    query = "select * from TABLE_A where ATTR IN (PARAM)";

现在可以使用executeQuery()方法执行查询。只要确保在查询中没有“PARAM”这个词。您可以使用特殊字符和字母的组合来代替单词“PARAM”,以确保查询中不可能出现这样的单词。希望你得到了答案。

注意:虽然这不是一个准备好的查询,但它完成了我希望代码完成的工作。