在 Java 中的 PreparedStatement 中使用大于或等于 (>=)

Using larger than or equal (>=) to in PreparedStatement in Java

我有一个 SQL 语句,看起来像这样 SELECT * FROM VAL WHERE VAL_VALUTA >= CHF ORDER BY VAL_VALUTA ASC LIMIT 10。该语句工作正常,现在我尝试在 Java 中使用它和 PreparedStatement 以及以下代码(我省略了连接和 try 块)

String sqlQuery = "SELECT * FROM VAL WHERE VAL_VALUTA ? ? ORDER BY VAL_VALUTA ASC LIMIT ?";

PreparedStatement statement = connection.prepareStatement(sqlQuery);
statement.setString(1, searchDirection);
statement.setString(2, currencyCode);
statement.setInt(3, numberOfCurrenciesReturned);

当我打印 statement:

时,我在控制台中得到以下输出

sql : 'SELECT * FROM VAL WHERE VAL_VALUTA ? ? ORDER BY VAL_VALUTA ASC LIMIT ?', parameters : ['>=','CHF',5]

一切看起来都很好,但 returns 什么都没有。如果我在 sqlQuery 中硬编码 >= 那么它工作正常但我宁愿不这样做,因为我需要根据不同的条件将它更改为 <=.

有什么办法解决这个问题还是我需要硬编码?我正在使用 Java 8、DBCP2 和 MariaDB。

使用这个

String signString  = "<=" ;
String sqlQuery = "SELECT * FROM VAL WHERE VAL_VALUTA ? "+ signString +" ? ORDER BY VAL_VALUTA ASC LIMIT ?";

根据需要更改 signString

运算符不能参数化。我建议使用两种不同的sqlQuery字符串,一种小于,一种大于,根据自己需要满足的条件来切​​换。

使用 2 个不同的 PreparedStatement

PreparedStatement 自动转义参数输入,所以你放在那里的任何内容都不会被视为实际的 greater-than-or-equal 比较。这是理想的行为,拥有多个 PreparedStatement 的开销不足以担心(大多数程序都有很多语句)。

试试这样的东西:

private static final String sqlSelectGreaterOrEqual = "SELECT * FROM VAL WHERE VAL_VALUTA >= ? ORDER BY VAL_VALUTA ASC LIMIT ?";
private static final String sqlSelectLessOrEqual = "SELECT * FROM VAL WHERE VAL_VALUTA <= ? ORDER BY VAL_VALUTA ASC LIMIT ?";
private PreparedStatement psSelectGreaterOrEqual = null;
private PreparedStatement psSelectLessOrEqual = null;

// ... later in your program, or in your constructor, or some method

psSelectGreaterOrEqual = connection.prepareStatement(sqlSelectGreaterOrEqual);
psSelectLessOrEqual = connection.prepareStatement(sqlSelectLessOrEqual);

// ... later in your program in some method
public List<String> selectGreaterOrEqual(String criteria) {
    ResultSet rs = null;
    List<String> results = new ArrayList<String>();
    if (psSelectGreaterOrEqual != null) {
        try {
            psSelectGreaterOrEqual.setString(1, criteria);
            rs = psSelectGreaterOrEqual.executeQuery();
            if (rs != null && rs.isBeforeFirst()) {
                while(rs.next()) {
                    results.add(rs.getString(1));
                    // etc... 
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (rs != null) rs.close();
        }
    }
    return results;
}

现在,稍后在您的程序中,只需使用任何一个有意义的,即。也许不同的方法调用会调用一个或另一个,或者 if 语句根据其他一些程序逻辑决定使用哪个,等等。

您可以尝试对您的查询进行标记,然后将标记替换为您的 searchDirection 字符串。

String sqlQuery = "SELECT * FROM VAL WHERE VAL_VALUTA %SEARCHDIRECTION% ? ORDER BY VAL_VALUTA ASC LIMIT ?";

sqlQuery = sqlQuery.replaceAll("%SEARCHDIRECTION%", searchDirection);

PreparedStatement statement = connection.prepareStatement(sqlQuery);
statement.setString(1, currencyCode);
statement.setInt(2, numberOfCurrenciesReturned);

先说说为什么会这样

查询本身及其参数之间存在差异。 >=是查询的一部分,5是参数。

这是为什么?好吧,准备好的语句试图保护您免受可能作为参数传递到查询中的任何危险。假设有人给你传递了类似 IS NULL; DROP TABLE VAL_DATA ... 而不是字符串 >= 的东西。你最终会 运行 SELECT * FROM VAL WHERE VAL_VALUTA IS NULL; DROP TABLE VAL_DATA;。这将杀死整个 VAL_DATA table。为避免此类安全风险(和诚实的错误),准备好的语句会转义参数值,并通过动态生成查询字符串来诱使它们这样做可能不是最好的主意,尽管那会起作用,这也是大多数其他答案所建议的你知道。

我认为最好和最安全的解决方案是针对不同的情况进行一些不同的查询。没有那么多案例。

String queryLE = "SELECT * FROM VAL WHERE VAL_VALUTA <= ? ORDER BY VAL_VALUTA ASC LIMIT ?";
String queryEQ = "SELECT * FROM VAL WHERE VAL_VALUTA == ? ORDER BY VAL_VALUTA ASC LIMIT ?";

等..

这简单、安全、安全。无法仅通过传递参数来破坏整个数据库。

vijay所说:运算符不能参数化

所以使用这个:

String sqlQuery = "SELECT * FROM VAL WHERE VAL_VALUTA " + searchDirection + " ? ORDER BY VAL_VALUTA ASC LIMIT ?";

PreparedStatement statement = connection.prepareStatement(sqlQuery);
statement.setString(1, currencyCode);
statement.setInt(2, numberOfCurrenciesReturned);