2

我正在创建一个基于 Web 的小型工具,允许用户以各种方式查询大型查找表。由于它是一个小工具,我使用的是 JSP/Servlets。

查找表的定义如下:

第 1 列 | 第 2 列 | 第 3 列 | 日期 | 用户 | 数数

用户可以按列值或范围查询。此外,结果可以按特定列排序。因为该表有几十万条记录,并且增长迅速,所以我使用 Oracle 的 ROWNUM 并且只返回一小部分结果。

我有一个从用户那里获取搜索条件的表单页面。我根据一系列条件生成查询,例如:

query = "SELECT * FROM mytable WHERE 1=1 "
if(searchCriteria1 != "")
    query += "AND column1='searchCriteria1' "
if(searchCriteria2 != "")
    query += "AND column2='searchCriteria2' "
if(searchCriteria2 != "")
    query += "AND column2='searchCriteria2' "
if(searchCriteria3 != "")
    query += "AND column3='searchCriteria3' "
if((searchCriteria4 != "") && (searchCriteria5 != ""))
    query += "AND date>='searchCriteria4' AND date<='searchCriteria5' "
etc...

(这只是简化的伪代码)

在显示第一个结果页面后处理排序。用户单击该页面的列标题以按该列排序。这将是回发并查询数据库。基本上,我在上面运行相同的代码,但最后是这样的:

if(sortColumn1)
    query += "ORDER BY column1"
if(sortColumn2)
    query += "ORDER BY column2"
if(sortColumn3)
    query += "ORDER BY column3"

因此,正如您可能想象的那样,我的查询构建代码在所有这些不同的条件下都很长。关于更好的方法来做到这一点的任何建议?

4

5 回答 5

3

字符串连接不是 SQL 的最佳选择。您可以做的最好的事情是使用QueryDSLJOOQ并以 OO 方式进行。我对 QueryDSL 比较熟悉。看看这里的例子。

SQLQuery query = new SQLQueryImpl(connection, dialect); 
query.from(myTable);

BooleanBuilder wheres = new BooleanBuilder();

if(notBlank(searchCriteria1))
   wheres.and(myTable.column1.eq(searchCriteria1));
if(notBlank(searchCriteria2))
   wheres.and(myTable.column2.eq(searchCriteria2));
if(notBlank(searchCriteria4) && notBlank(searchCriteria5))
   wheres.andAllOf(myTable.date.goe(searchCriteria4),  myTable.date.loe(searchCriteria5));  //you may want to use myTable.date.between(...)

if (...) {
   query.orderBy(myTable.column1.asc());
} else if (...){
   query.orderBy(myTable.column2.asc());
}

query.limit(100); //it is good to limit a result
query.list(myTable.all());

至于 SQL 注入查询引擎将在构造 SQL 时将您的参数包装在命名参数中。

于 2012-10-25T22:29:17.937 回答
2

首先,不要使用简单String的查询。您应该使用PreparedStatement,它可以保护您免受SQL 注入(恶意用户破坏易受攻击系统的一种非常简单的方法)。

if()... else if()...其次,如果您的输入确实如此复杂,那么您将无法避免阻塞。看起来你的方法做得比它应该做的要多得多。考虑根据用户想要运行的查询类型调用不同的方法。我已经实现了许多 DAO,在向子句if添加行时,无法绕过块中的所有这些空检查。ANDWHERE

但是,您绝对可以做的一件事是将大部分查询写在一个private static final String带有问号的常量中,您希望参数为 ( ?),根据用户输入附加您需要的其他条件,然后PreparedStatement直接从中构建。一旦你制作了s PreparedStatement,你可以使用各种 setter 命令来填充那些?s。这对代码进行了相当多的整理。

于 2012-10-25T22:37:56.890 回答
1

永远不要使用字符串连接将用户输入的数据放入您的查询中。您应该在查询中使用命名参数或位置参数并传递参数。

于 2012-10-25T22:21:06.763 回答
0

我认为向后端发送请求进行排序不是一个好主意。js中有很多插件可以对表格进行排序,可以使用。

于 2012-10-25T22:16:24.477 回答
0

从简单的角度

如果您知道所有类型的列,则可以使用数组和表来使此代码更多地由数据驱动。

于 2012-10-25T22:16:41.660 回答