我的用户界面有 9 个字段,每个字段代表数据库表中的一列。 所以问题是我需要涵盖 9 个字段的所有可能组合并向数据库发送特定查询。 例子 : 如果用户输入 2 个字段,我将返回数据库中与这 2 个项目的组合匹配的所有项目。 如果用户输入 3 个字段,我将返回数据库中与这 3 个项目的组合相匹配的所有项目。 如果算一下,显然组合有100+。 使用带有 JDBC 驱动程序的 JAVA 和 MySQL,提供了可确保 SQL 注入安全的准备语句。 但这样一来,我应该制作 100 多个函数来覆盖所有组合,并且代码会重复。
我如何解决: 我创建了一个查询生成器,它接受用户输入的输入并创建一个 SQL 查询作为字符串。 然后我使用 Statement Class 将其传递给数据库。这样我涵盖了所有可能的组合,但我必须自己从零开始制作 SQL 注入保护,通常这是针对我确信它已经解决的问题的自定义解决方案。
如果有官方方法,请告诉我!
SELECT table.*
FROM table
JOIN ( SELECT @column1 AS column1
, @column2 AS column2
......
, @column9 AS column9
) AS criteria ON ( table.column1 = criteria.column1 OR criteria.column1 IS NULL)
AND ( table.column2 = criteria.column2 OR criteria.column2 IS NULL)
..........
AND ( table.column9 = criteria.column1 OR criteria.column9 IS NULL)
如果用户已输入某些列的值,则您可以在查询中提供输入的条件,否则您提供 NULL (
command.Parameters.AddWithValue("@columnX", (object)value ?? DBNull.Value)
)。
基本上有两种方法可以解决这个问题。
第一个使用一个带有 OR 条件的语句来处理缺失的条件。
第二种方法使用动态生成的语句,仅包含具有给定值的谓词。
第一个解决方案的缺点是您得到one语句,即处理所有输入的一个执行计划。
第二种解决方案允许根据输入选择正确的执行计划。缺点是您会遇到“不同数量”的绑定变量,这在技术上难以处理。 这里出现了
Tom Kyte多年来流行的想法 您为每个选择生成谓词,但取决于是否给出了值:
column = :bind_variable -- if the value is passed
(1=1 or :bind_variable is NULL) – if no value is NOT passed
快捷逻辑消除了没有值的谓词,但您在准备好的语句中获得了绑定变量的完整数量。三栏全部通过的例子
where
col1 = :1 and
col2 = :2 and
col3 = :3
where
col1 = :1 and
(1=1 or :2 is NULL) and
(1=1 or :3 is NULL)
where
(1=1 or :1 is NULL) and
(1=1 or :2 is NULL) and
(1=1 or :3 is NULL)
这里是第二个示例的 Oracle 执行计划,显示仅评估
col1
谓词,所有其他谓词都被丢弃。类似对 PostgreSQL 有效,我没有测试 MySQL。
------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 18 | 4 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID BATCHED| TEST | 1 | 18 | 4 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | COL1_IDX | 1 | | 3 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("COL1"=TO_NUMBER(:1))
对于第三个查询(无条件),您以
full table scan
结尾
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1000K| 17M| 896 (1)| 00:00:01 |
| 1 | TABLE ACCESS FULL| TEST | 1000K| 17M| 896 (1)| 00:00:01 |
--------------------------------------------------------------------------
因此,如果结果的基数高度依赖于选择,则这种方法更适合,一刀切OR
谓词解决方案
。