【问题标题】:The proper way to prepare a dynamic Statement in Java在 Java 中准备动态语句的正确方法
【发布时间】:2021-11-21 00:24:54
【问题描述】:

我正在根据通过查询字符串传递的值准备一条 SQL 语句。 (我正在使用 Play!框架。基本上我遇到的(不是真正的问题,只是我不太喜欢的东西)是当我想在 SQL 字符串中使用 ? 并稍后设置它们时动态值。

这就是我所拥有的:

String sql = "SELECT * FROM foobar_table WHERE";

if ( foo != 0 )
    sql += " AND foo=?";
if ( !bar )
    sql += " AND bar=?";

try{
    PreparedStatement getStmt = con.prepareStatement(sql);
    if ( foo != 0 )
        getStmt.setInt(1,foo);
    if ( foo != 0 && !bar )
        getStmt.setBoolean(2, bar);
    else
        getStmt.setBoolean(1, bar);
} catch (SQLException e ){
    e.printStackTrace();
}

这确实有效,但正如您所见,它不是很直观。当有 2 个动态值时没关系,但是当你达到 5 或 6 个时,这会变得很荒谬。

有没有更简单的方法让它更灵活,以便我知道如何以更好的方式填写所有?

【问题讨论】:

    标签: java sql jdbc prepared-statement playframework-2.0


    【解决方案1】:

    一个例子(评论太长了):

    String sql = "SELECT * FROM foobar_table WHERE 1 = 1 ";
    ArrayList paramList = new ArrayList();
    
    if ( foo != 0 ) {
        sql += " AND foo=?";
        paramList.add(foo);
    }
    
    if ( !bar ) {
        sql += " AND bar=?";
        paramList.add(bar);
    }
    
    try{
    
        PreparedStatement getStmt = con.prepareStatement(sql);
    
        int index = 1;
    
        for (Object param : paramList) {
            getStmt.setObject(index, param);
            index++;
        }
    
        // execute
    
    } catch (SQLException e ){
        e.printStackTrace();
    }
    

    【讨论】:

    • 这样最好.. 又好又干净。谢谢
    【解决方案2】:

    可能是这样的(只是粗略的代码,但你明白了):

        class Param{
            final int type;
            final Object value;         
            Param(int type, Object value){
                this.type = type;
                this.value = value;
            }
        }
    
        final List<Param> params = new ArrayList<>();
    
        final StringBuilder sql = new StringBuilder("SELECT * FROM bcu_venue_events WHERE 1=1");
        int foo = 0;
        boolean bar = true;             
        if (foo != 0){
            sql.append(" AND foo=?");
            params.add(new Param(Types.INTEGER, foo));
        }       
        if (!bar){
            sql.append(" AND bar=?");
            params.add(new Param(Types.BOOLEAN, bar));
        }
        try(Connection conn = null; PreparedStatement getStmt = conn.prepareStatement(sql.toString())) {            
            for(int i = 0; i < params.size(); i++){
                Param p = params.get(i);
                getStmt.setObject(i + 1, p.value, p.type);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    

    【讨论】:

      【解决方案3】:

      这个怎么样:

      String sql = "SELECT * FROM foobar_table WHERE 1=1";
      
      if ( foo != 0 )
          sql += " AND foo=" + foo;
      if ( !bar )
          sql += " AND bar=" + bar;
      
      try{
          PreparedStatement getStmt = con.prepareStatement(sql);
      } catch (SQLException e ){
          e.printStackTrace();
      }
      

      【讨论】:

      • 这不是让所有东西都可以注入吗?准备声明的重点是避免这种情况。
      • 您可以在输入此代码块之前检查参数。你没有提到应该假设变量是不安全的。
      • 以此为基础,参数化,同时也建立一个对象的ArrayList,稍后设置:sql += " AND foo = ?"; paramList.add(foo);
      • 这是我在 php 中的做法,但由于 Java 是严格类型的,这将不起作用。 foo 可以是 String、boolean、int、Float 或 double
      • for (Object param : paramList) { preparedStatment.setObject(param); }
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-07
      • 2012-01-28
      • 2015-10-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多