如何处理对数据库进行超过 100 种组合的 SQL 查询?

问题描述 投票:0回答:2

我的用户界面有 9 个字段,每个字段代表数据库表中的一列。 所以问题是我需要涵盖 9 个字段的所有可能组合并向数据库发送特定查询。 例子 : 如果用户输入 2 个字段,我将返回数据库中与这 2 个项目的组合匹配的所有项目。 如果用户输入 3 个字段,我将返回数据库中与这 3 个项目的组合相匹配的所有项目。 如果算一下,显然组合有100+。 使用带有 JDBC 驱动程序的 JAVA 和 MySQL,提供了可确保 SQL 注入安全的准备语句。 但这样一来,我应该制作 100 多个函数来覆盖所有组合,并且代码会重复。

我如何解决: 我创建了一个查询生成器,它接受用户输入的输入并创建一个 SQL 查询作为字符串。 然后我使用 Statement Class 将其传递给数据库。这样我涵盖了所有可能的组合,但我必须自己从零开始制作 SQL 注入保护,通常这是针对我确信它已经解决的问题的自定义解决方案。

如果有官方方法,请告诉我!

java mysql jdbc prepared-statement sql-injection
2个回答
0
投票
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)
)。


0
投票

基本上有两种方法可以解决这个问题。

第一个使用一个带有 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谓词解决方案

© www.soinside.com 2019 - 2024. All rights reserved.