2012-03-30 100 views
2

我知道使用预准备语句有助于避免sql注入。我的问题是,准备好的声明通常是非常静态的。我遇到了一个问题,在运行时根据用户输入构建sql-query的where子句。根据哪些输入字段被填充,我必须将相关语句添加到where子句。如何通过准备好的陈述来实现这一点?如何在Java中创建动态预准备语句?

回答

3

我想你可以根据他们想要查询的列动态地构建你准备好的语句,即使用一个StringBuffer和一个循环来根据需要的列建立它们。

为了提高效率,您应该将这些保存在某种内存查找中。所以你最终会得到一个Map或者其他准备好的语句集合,其中检索关键字是它们设计用于查询的列。

+0

好的,但这也意味着我也必须保留与我创建的SQL查询参数列表,因为值的添加只能与索引。我对吗? – Mnementh 2012-03-30 13:25:33

+0

是的,你需要保持参数列名在缓存中进行查找,你还需要保持他们的顺序或者以某种方式(字母?)预测顺序,以便知道哪个“?”用您的查询数据替换。希望这是有道理的,SQL不是我的第一语言:) – Jonathan 2012-03-30 13:31:06

+0

尽可能容易,但我可以管理。谢谢。 – Mnementh 2012-03-30 13:53:42

2

如果你只想要从sql注入保护,在运行时构造查询是好的,只要你不插入任何用户发送到查询(但插入子句,如果用户发送至少在字段中的东西是好)。

表现 - 我不知道。也许数据库会缓存准备好的语句,所以如果你再次构造完全相同,它会更快,否则它不会。我不知道如何找出答案。

+0

来自PreparedStatement的JavaDocs“表示预编译的SQL语句的对象”。基于此我不相信数据库来缓存它们,我宁愿自己缓存它们。如果当然你可以随时分析。但它可能会更快地实施缓存;) – Jonathan 2012-03-30 13:23:08

+0

acording http://www.theserverside.com/news/1365244/Why-Prepared-Statements-are-important-and-how-to-use-them-适当的缓存可以通过连接池完成。 – Alpedar 2012-03-30 13:58:09

0

如果您使用Hibernate,Criteria Queries API是避免使用字符串连接来构建SQL查询的好工具。使用普通的JDBC,你必须使用一个StringBuffer,就像@Jhonatan所说的那样。

2

如果您正在根据用户选择的选项创建查询中的where /和clause,那么我猜测,您已经知道要按顺序对查询进行哪些更改获取所需的数据。如果是这种情况,那么您可以创建方法,将用户要求的选项作为方法的参数,方法构建查询并返回该查询。

//something similar to the following 
public String buildQuery(int option){ 
    StringBuilder sb = new StringBuilder(); 
    sb.append("select fields from table"); 
    switch(option){ 
    case 1: 
    //build query and append to sb 
    sb.append("where clause for option1"); 
    case 2: 
    //build query and append to sb 
    sb.append("where clause for option2"); 
    default: 
    // build query using default 
    sb.append("default where clause"); 
    } 

    return sb.toString(); 
} 
// create the stored procedure 
PreparedStatement ps = conn.prepareStatement(buildQuery(2)); 
ResultSet rs = ps.executeQuery(); 

现在,如果你需要临时使用特定的用户在查询中输入的值,可以存储它们在列表或地图,然后进行设置。

ps.setString(1,list.get(0)); 
ps.setString(2,list.get(1)); 
ResultSet rs = ps.executeQuery(); 

有probbaly更elegeant解决问题,但我们有一个查询,使用用户的输入来构建查询记录的数据库的应用程序,它已经在过去两年工作的罚款。希望有所帮助。

-1

声明一个方法并通过该方法传递userinput。然后根据您在preparestement对象中的输入数据类型使用setStringsetLong