我有一个类似于SELECT * FROM VAL WHERE VAL_VALUTA >= CHF ORDER BY VAL_VALUTA ASC LIMIT 10
的SQL语句。该语句工作正常,现在我尝试在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]
一切看起来都不错,但什么都没有。如果我在>=
中对sqlQuery
进行硬编码,那么它可以正常工作,但我不愿意这样做,因为我需要将其针对不同条件更改为<=
。
有什么方法可以解决这个问题,还是需要对其进行硬编码?我正在使用Java 8,DBCP2和MariaDB。
答案 0 :(得分:4)
首先让我们谈谈为什么会这样做
查询本身与其参数之间存在差异。 >=
是查询的一部分,5
是参数。
为什么?那么准备好的语句试图保护您免受可能在查询中作为参数传递的任何危险。假设有人通过了IS NULL; DROP TABLE VAL_DATA ...
而不是字符串>=
。您最终会运行SELECT * FROM VAL WHERE VAL_VALUTA IS NULL; DROP TABLE VAL_DATA;
。这将终止整个VAL_DATA
表。为了避免这样的安全风险(和诚实的错误),准备好的语句可以逃避参数的值,并且通过动态生成查询字符串来欺骗它们可能不是最好的想法,尽管这样做可以解决这个问题。大多数其他答案建议你这样做。
我认为最好和最安全的解决方案是针对不同的案例进行一些不同的查询。这种情况并非如此。
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 ?";
等。
这很简单,安全且安全。仅通过传递参数就无法对整个数据库进行核对。
答案 1 :(得分:1)
操作员无法参数化。我建议使用两个不同的sqlQuery字符串,一个用于少于一个,一个用于大于,并根据您需要满足的条件在它们之间切换。
答案 2 :(得分:0)
使用此
String signString = "<=" ;
String sqlQuery = "SELECT * FROM VAL WHERE VAL_VALUTA ? "+ signString +" ? ORDER BY VAL_VALUTA ASC LIMIT ?";
根据需要更改signString
答案 3 :(得分:0)
使用2个不同的PreparedStatement
。
PreparedStatement
会自动转义参数输入,因此您放在那里的任何内容都不会被视为实际的大于或等于比较。这是理想的行为,并且有多个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语句根据其他一些程序逻辑决定使用哪个,等等。
答案 4 :(得分:0)
您可以尝试对查询进行标记,然后使用myList <- list(my_data_frame=my_data_frame)
# add attribute
attr(myList[[df_name]], "attr2") <- 2L
# check
attr(myList[[df_name]], "attr2")
[1] 2
# return to data.frame
my_data_frame <- myList[[df_name]]
# check regular data.frame
attr(my_data_frame, "attr2")
[1] 2
字符串替换该标记。
searchDirection
答案 5 :(得分:0)
如同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);