简体   繁体   English

如何在Java中创建动态的预处理语句?

[英]How to create a dynamic prepared statement in Java?

I know using prepared statements helps to avoid sql-injection. 我知道使用准备好的语句有助于避免sql-injection。 My problem is, that a prepared statement is usually very static. 我的问题是,准备好的语句通常非常静态。 I have a problem, where I build the where-clause of the sql-query at runtime, depending on user-input. 我有一个问题,我在哪里在运行时根据用户输入建立sql查询的子句。 Depending on which input-fields are filled I have to add the correspending statements to the where-clause. 根据填充的输入字段,我必须将相应的语句添加到where子句中。 How can this be realized with prepared statements? 用准备好的语句如何实现?

I guess you could dynamically build your prepared statements based on what columns they want to query, ie use a StringBuffer and a loop to build them based on the required columns. 我猜您可以根据要查询的列动态构建准备好的语句,即使用StringBuffer和循环根据所需的列来构建它们。

For efficiency you should keep these in some kind of in-memory lookup. 为了提高效率,您应该将它们保留在某种内存中查找中。 So you'd end up with a Map or other collection of prepared statements where the retrieval key is the columns they're designed to query against. 因此,您最终将获得Map或其他准备好的语句集合,其中检索键是设计用来对其进行查询的列。

If you are building the where/and clause(s) in your query based upon what what options the user selected then, I'm guessing, that you already know what changes will have to be made to the query in order get the desired data. 如果您要根据用户选择的选项在查询中构建where / and子句,那么我想您已经知道必须对查询进行哪些更改才能获得所需的数据。 。 If that is the case then you could create method that takes in the option the user asked for as a parameter to the method, the method builds the query and returns that query. 如果是这种情况,那么您可以创建一个方法,该方法采用用户要求的选项作为该方法的参数,该方法将构建查询并返回该查询。

//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();

Now if you need to use specific user entered values in the query you can store them temporarily in a list or map and then set them. 现在,如果您需要在查询中使用特定的用户输入值,则可以将它们临时存储在列表或映射中,然后进行设置。

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

There's probbaly a more elegeant solution to the problem but we have an application that queries the database for records using the user's input to build the queries and it's been working fine for the last two years. 可能有一个更好的解决方案,但是我们有一个应用程序可以使用用户的输入来查询查询数据库中的记录,以建立查询,并且在过去两年中一直运行良好。 Hope that helps. 希望有所帮助。

If you only want the protection from sql-injection, constructing the query at runtime is OK, as long as you don't insert anything user sent into the query (but inserting clause if user sent at least something in field is ok). 如果只希望免受sql-injection的影响,则在运行时构造查询是可以的,只要您不向查询中插入用户发送的任何内容即可(但如果用户至少在字段中发送了内容,则插入子句即可)。

Performance - I don't know. 性能-我不知道。 Maybe DB will cache prepared statements, so if you construct exactly same again, it will be faster, or it won't. 也许DB会缓存准备好的语句,所以如果再次构造完全相同的语句,它将更快,或者不会。 I dont know how to find out. 我不知道如何找出答案。

If you're using Hibernate, Criteria Queries API is a nice tool for avoiding String concatenation to build SQL Queries. 如果您使用的是Hibernate,则Criteria Queries API是一个不错的工具,可避免使用String串联来构建SQL查询。 With plain JDBC, you'll have to go with a StringBuffer as @Jhonatan said. 使用纯JDBC,您必须使用@Jhonatan所说的StringBuffer。

Declare one method and pass the userinput through that method. 声明一个方法,并通过该方法传递用户输入。 Then use setString or setLong depending on your input data type within the preparedstement object. 然后根据setLong对象中的输入数据类型使用setStringsetLong

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM