我正在开发一个我经常访问数据库的portlet。我必须以某种方式指定查询,这提供了过滤作为对用户输入的反应的可能性。目前用于过滤的参数是两个,但是这个数字可以在将来增长。
目前,我的构建工作非常适合所有输入,但是,我不认为我正在以正确/有效的方式进行,因为我不使用预准备语句并且只是手动构建查询。
这是我的代码示例( serviceFilter 是一个arrayList而 typeFlag 是一个字符串)
private String prepareQuery() {
String query = "SELECT * from messages ";
// check filters
if (!typeFlag.equals("ALL")) {
if (typeFlag.equals("XML")) {
query += "WHERE type='" + TYPE_XML + "'";
} else {
query += "WHERE type='" + TYPE_JAVA + "'";
}
}
// lets see if user specifies some service filtering
if (serviceFilter.size() > 0) {
if (!typeFlag.equals("ALL")) {
query += " AND (";
} else {
query += " WHERE (";
}
for (int i = 0; i < serviceFilter.size(); i++) {
if (i>0) {
query += " OR ";
}
String service = serviceFilter.get(i);
System.out.println("Filter: " + service);
query += "sender='" + service + "' OR receiver='" + service + "'";
}
query += ")";
}
query += " ORDER BY id DESC LIMIT " + String.valueOf(limit);
System.out.println(query);
return query;
}
第一个问题是,这无法阻止SQL注入(这不会是一个大问题,因为所有输入都来自checkBoxes和scrollbars,所以用户实际上并没有输入任何内容)。我不确定如何在这里使用预处理语句,因为我的arrayList的填充可能很长并且每个查询都会更改。
由于这个事实,查询本身可能会变得非常长。以下是仅针对两个参数的查询示例(想象这是20个项目):
SELECT * from messages WHERE (sender='GreenServiceESB#GreenListener' OR receiver='GreenServiceESB#GreenListener' OR sender='queue/DeadMessageQueue' OR receiver='queue/DeadMessageQueue') ORDER BY id DESC LIMIT 50
所以基本上,我的问题是:这是一种构建我的查询的有效方法(可能不是,正确)?你会建议采用什么方法?
PS:我正在使用JDBC连接到db并执行查询,如果它以任何方式重要...
感谢您的任何提示!
答案 0 :(得分:1)
如果你想使用像
这样的东西 create.selectFrom(BOOK)
.where(PUBLISHED_IN.equal(2011))
.orderBy(TITLE)
而不是
SELECT * FROM BOOK
WHERE PUBLISHED_IN = 2011
ORDER BY TITLE
你可以期待http://www.jooq.org/。它将简化您的代码,您可以避免“if(something){sql + =”WHERE ...“}”之类的内容。这是反模式,在可能的情况下不应使用。
答案 1 :(得分:1)
首先,您暗示了一个问题 - 不使用PreparedStatement
。获取用户输入并直接在SQL语句中使用它会打开一个SQL注入攻击站点。
我认为你想要的是:
select * from (
select *, row_number over (order by id_desc) as rowNum
from messages
where sender in (?,?,?,?,?,?,?,?) --8, 16 or however many ?'s you'll need
or receiver in (?,?,?,?,?,?,?,?)
) results
where rowNum between (1 and ?)
order by rowNum
现在,您将参数绑定到用户输入的任何内容,如果您在IN
运算符剩余的位置有额外的位置,则将它们绑定到某些不能(或可能不会)的值在您的表格中,例如null
或HiMom#2$@
。如果需要支持任意数量的值,则多次运行查询并自行将结果排序到内存中。
至于row_number
函数,这在MySQL中可能不起作用(我不是MySQL人),但它确实有一个等价物(或者可能limit
可以参数化,我不知道。