1

我有一个方法' getAllIDs()'用于获取数据库中特定表的 ID。它在我的项目中被许多方法使用。

public static int[] getAllIDs (String TableName, String WhereClause, String trxName)
    {
        ArrayList<Integer> list = new ArrayList<Integer>();
        StringBuffer sql = new StringBuffer("SELECT ");
        sql.append(TableName).append("_ID FROM ").append(TableName);
        if (WhereClause != null && WhereClause.length() > 0)
            sql.append(" WHERE ").append(WhereClause);
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try
        {
            pstmt = DB.prepareStatement(sql.toString(), trxName);
            rs = pstmt.executeQuery();
            while (rs.next())
                list.add(new Integer(rs.getInt(1)));
        }
}

Whereclause 是查询的条件部分。由于这个 whereclause,有可能进行 sql 注入。所以我需要修改这个方法来使用prepared statement参数设置来设置参数。我遇到的问题是因为 ' getAllIDs()' 不知道每个 where 子句有多少参数。

每个 where 子句的参数都不同,它可以是任意数字。对于某些类,参数将为 3,对于某些类,参数为 2,等等具有不同的数据类型。那么我如何使用 setstring()、setint() 等。用我发布的代码解释一下。

4

5 回答 5

5

Pass an additional PreparedStatementBinder argument to the method:

public interface PreparedStatementBinder {
    /**
     * Binds all the arguments to the given prepared statement
     */
    public void bindArguments(PreparedStatement statement) throws SQLException;
}

The caller will have to pass a where clause (such as "foo = ? and bar = ?"), and an instance of this interface, such as

new PreparedStatementBinder() {
    @Override
    public void bindArguments(PreparedStatement statement) throws SQLException {
        statement.setString(1, theFoo);
        statement.setInt(2, theBar);
    }
}
于 2012-09-07T10:27:34.333 回答
2

There are several possible ways to do this. A simple one could be to make the WhereClause behave like a map where you keep parameter names and values. Then you define the prepared statement template based on the keys and fill it with values. You may need a smarter data structure if you want to join the where clauses with AND/OR keywords or use different operators for each clause: = / < / > / NOT / IS NULL etc, all this dynamically.

If you can make use of more sophisticated libraries, the Criteria API in Hibernate or other ORM tools can be really suitable for this kind of usecase.

于 2012-09-07T10:28:21.820 回答
1

听起来您可能正在构建对象关系映射器 (ORM)、查询生成器或类似的东西。

如果是这样,请考虑使用现有的解决方案来解决问题,因为这些解决方案比看起来更难解决。

考虑 JPA 或 Hibernate Criteria API;它们很丑陋,但很全面。还有许多其他的程序化查询生成器,并非所有这些都与 ORM 相关联。

不要重新发明这个轮子。现在可能看起来很容易,但您将继续遇到限制,直到您的设计开始变得非常复杂和笨拙。

于 2012-09-07T10:33:14.237 回答
0

也许我把你们都弄错了,但我根据我从你的陈述中得出的结论提出了一个解决方案。使Where-Clause参数可选,如

public static int[] getAllIDs (String tableName, String... whereClause, String trxName) 

如果它们出现,请将它们设置为

 for(String param:whereClause)
  {
       pst.setParameter("Param-name",param);
  }
于 2012-09-07T10:21:57.750 回答
0

大多数人建议使用完整的 ORM 解决方案,例如 Hibernate 或 JPA。如果您只需要一个查询来集成其中任何一个,则需要付出一些努力,但我猜这不是唯一受 SQL 注入影响的查询,并且该设置可以重用于部分/大多数/全部应用程序中的查询。

然而,一个快速而肮脏的解决方案是为标准的每个变体创建方法,如果它们只有几个。每个方法都会接受所需参数的确切类型,并知道如何将这些参数绑定到preparedStatement。类中可能有一个工厂方法(由这些方法调用),它将传递表名、txn 名称等,并返回 SELECT 和 FROM 子句。

无论您选择哪种解决方案,getAllIds() 的调用者都需要更改。

于 2012-09-07T13:53:48.560 回答