在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表以使锁定或其他高开销保护最小化。
这适用于我(伪docode):
public class SqlHelper
{
public static final ArrayList<String>platformList = new ArrayList<>(Arrays.asList("iOS","Android","Windows","Mac"));
public static final String testQuery = "select * from devices where platform_nm in (:PLATFORM_NAME)";
}
指定绑定:
public class Test extends NamedParameterJdbcDaoSupport
public List<SampleModelClass> runQuery()
{
//define rowMapper to insert in object of SampleClass
final Map<String,Object> map = new HashMap<>();
map.put("PLATFORM_LIST",DeviceDataSyncQueryConstants.platformList);
return getNamedParameterJdbcTemplate().query(SqlHelper.testQuery, map, rowMapper)
}
没有简单的办法。
如果目标是保持较高的语句缓存比(即不是每个参数都创建一条语句),您可以执行以下操作:
创建带有几个参数(例如10个)的语句:
... 一个在 (?,?,?,?,?,?,?,?,?,?) ...
绑定所有实际参数
setString(1、“foo”);
setString(2,“酒吧”);
其余的绑定为NULL
Types.VARCHAR setNull (3)
...
Types.VARCHAR setNull (10)
NULL从不匹配任何东西,因此它会被SQL计划构建器优化。
当你将List传递给DAO函数时,逻辑很容易自动化:
while( i < param.size() ) {
ps.setString(i+1,param.get(i));
i++;
}
while( i < MAX_PARAMS ) {
ps.setNull(i+1,Types.VARCHAR);
i++;
}