1

我正在开发一个经常访问数据库的 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 注入(这不会是一个大问题,因为所有输入都来自复选框和滚动条,因此用户实际上并没有输入任何内容)。我不确定如何在这里使用准备好的语句,因为我的 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 并执行查询,如果它在任何方面都很重要......

感谢您的任何提示!

4

2 回答 2

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运算符中有多余的位置,您可以将它们绑定到一些不能(或可能不会)在您的表中的值,例如nullor HiMom#2$@。如果您需要支持任意数量的值,您可以多次运行查询并自己在内存中对结果进行排序。

row_number函数而言,它可能在 MySQL 中不起作用(我不是 MySQL 人),但它确实有一个等价物(或者它可能是limit可参数化的,我不知道。

于 2013-06-03T09:24:02.243 回答
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 ..." }”之类的事情。这是反模式,尽可能不要使用。

于 2013-06-03T08:09:35.873 回答