java PreparedStatement IN子句替换?
对于将SQL IN
子句与java.sql.PreparedStatement
实例一起使用,最好的解决方法是什么?由于SQL注入攻击安全问题,多个值不支持该子句:一个?
占位符代表一个值,而不是一个值列表
考虑下面的SQL语句:
SELECT my_column FROM my_table where search_column IN (?)
使用preparedStatement.setString( 1, "'A', 'B', 'C'" );
基本上是一种不起作用的尝试,试图从一开始就解决使用?
的原因
有哪些解决办法
# 1 楼答案
一个令人不快的解决方法是使用嵌套查询,但肯定是可行的。创建一个包含列的临时表MYVALUES。将值列表插入MYVALUES表。然后执行
丑陋,但如果你的价值观清单很大,这是一个可行的选择
这种技术的另一个优点是,如果数据库不缓存准备好的语句,优化器可能会提供更好的查询计划(检查一个页面是否有多个值,每个值只能检查一次,等等),这样可以节省开销。您的“插入”需要批量完成,MYVALUES表可能需要调整,以具有最小的锁定或其他高开销保护
# 2 楼答案
in()运算符的局限性是万恶之源
它适用于琐碎的情况,您可以通过“自动生成准备好的语句”来扩展它,但它总是有其局限性
in()方法在某些情况下已经足够好了,但还不够可靠:)
防火箭的解决方案是在一个单独的调用中传递任意数量的参数(例如,通过传递一个clob的参数),然后使用视图(或任何其他方式)在SQL中表示这些参数,并在where条件中使用
这里有一种蛮力变体http://tkyte.blogspot.hu/2006/06/varying-in-lists.html
然而,如果可以使用PL/SQL,这种混乱会变得相当整洁
然后可以在参数中传递任意数量的逗号分隔的客户ID,并且:
这里的诀窍是:
该视图看起来像:
aux_在_列表中的位置。getpayload指的是原始输入字符串
一种可能的方法是传递pl/sql数组(仅由Oracle支持),但是不能在纯sql中使用这些数组,因此始终需要一个转换步骤。转换不能在SQL中完成,因此,毕竟,以字符串形式传递包含所有参数的clob并在视图中转换它是最有效的解决方案
# 3 楼答案
没有简单的方法。 如果目标是保持语句缓存比率高(即不为每个参数计数创建语句),则可以执行以下操作:
创建一个包含几个(例如10个)参数的语句:
。。。其中A在(?,,,,,,,,,,,,,,,,,,,?)
绑定所有实际参数
设置字符串(1,“foo”); 设置管柱(2,“巴”)
将其余的绑定为NULL
setNull(3,Types.VARCHAR) ... setNull(10,Types.VARCHAR)
NULL从不匹配任何内容,因此它会被SQL计划生成器优化
当您将列表传递给DAO函数时,逻辑很容易自动化:
# 4 楼答案
PostgreSQL的解决方案:
或者
# 5 楼答案
您可以使用
Collections.nCopies
生成占位符集合,并使用String.join
将它们连接起来:# 6 楼答案
对各种可用选项的分析,以及每种选项的优缺点都是可用的
建议的选项包括:
SELECT my_column FROM my_table WHERE search_column = ?
,为每个值执行它,并在客户端合并结果。只需要一份准备好的声明。缓慢而痛苦李>SELECT my_column FROM my_table WHERE search_column IN (?,?,?)
并执行它。列表中的每种大小都需要一份准备好的声明。快速而明显李>SELECT my_column FROM my_table WHERE search_column = ? ; SELECT my_column FROM my_table WHERE search_column = ? ; ...
并执行它。[或使用UNION ALL
代替这些分号。--ed]要求列表中每种大小都有一条准备好的语句。速度太慢了,比WHERE search_column IN (?,?,?)
还差,所以我不知道为什么博主会这么建议李>SELECT my_column FROM my_table WHERE search_column IN (1,2,3,4,5,6,6,6,6,6)
。任何体面的服务器都会在运行查询之前优化掉重复的值李>这些选项都不理想
如果您使用的是JDBC4和支持
x = ANY(y)
的服务器,那么最好的选择是使用PreparedStatement.setArray
作为described here不过,似乎没有任何方法可以让
setArray
在列表中工作有时SQL语句在运行时加载(例如,从属性文件加载),但需要可变数量的参数。在这种情况下,首先定义查询:
接下来,加载查询。然后在运行之前确定参数的数量。参数计数已知后,运行:
例如:
对于某些不支持通过JDBC 4规范传递数组的数据库,此方法可以帮助将慢速
= ?
转换为快速IN (?)
子句条件,然后可以通过调用any
方法来扩展该条件