代码之家  ›  专栏  ›  技术社区  ›  WolfmanDragon

嵌套PreparedStatements的最佳实践是什么?

  •  1
  • WolfmanDragon  · 技术社区  · 16 年前

    我有几个实例,其中一部分旧的SQL语句是基于依赖关系的。例如。

    if (x !=null)
    {
      SQL = "SELECT z WHERE x > y";
    }
    else
    {
      SQL = "SELECT z WHERE x <= y";
    } 
    
    SQL2 = SQL + " JOIN a ON b";
    

    我正在用这个遗留代码创建PreparedStatements。这里的最佳实践是什么?我应该为var-sql创建一个PreparedStatement并将其嵌套在sql2中吗?应该有多个基于sql2的PreparedStatement而不嵌套,还是有一些完全不同的内容?

    代码比示例复杂得多,因为在许多长而复杂的SQL查询中都会重用sql var。

    编辑:项目设计需要使用PreparedStatements,目前我没有使用库的选择。

    6 回复  |  直到 16 年前
        1
  •  4
  •   Community CDub    8 年前

    >我应该为var sql创建一个PreparedStatement并将其嵌套在sql2中吗

    >或者是否存在基于sql2的多个PreparedStatements而不嵌套

    是的

    此外:如果您可以为每个查询创建一个字符串,那就更好了。我真的不喜欢把SQL和代码混合在一起。它使调试和理解变得更加困难,您不能复制/粘贴到SQL工具来轻松测试它。通过将SQL与代码分离,您可以将查询与操作(实际获取)分离开来,这样更容易维护。另外,如果代码不是你的,就更容易理解了。

    看起来像是在重复字符串并不重要,关键是要尽可能地简化语句。

    我会这样做:

    final class DatabaseQueries {
        public final static String SOME_SCENARIO       = "SELECT z WHERE x > y JOIN A, B ";
        public final static String SOME_OTHER_SCENARIO = "SELECT z WHERE x <= y JOIN A, B";
     }
    

    然后在课堂上使用它:

     PreparedStatement pstmt = getCon().prepareStatement( getQuery() );
    
    
     private String getQuery() { 
         if( x != null ) { 
              return DatabaseQueries.SOME_SCENARIO;
         } else { 
               return DatabaseQueries.SOME_OTHER_SCENARIO;
         }
     }
    

    在创建“databasequeries”类时,您会发现您重复了大量的字符串,我认为用其他常量替换某些部分是可以的。

    final class DataBaseQueries { 
        // this one is private
        private final static String JOIN_A_B = " join A, B ";
        public final static String SOME_SCENARIO       = "SELECT z WHERE x > y " + JOIN_A_B ;
        public final static String SOME_OTHER_SCENARIO = "SELECT z WHERE x <= y " + JOIN_A_B ;
    
    }
    

    这里的重点是使事情简单化。这是第一步。在第二步中,您可以创建一个类来创建那些非常复杂的查询,但可能是Yagni。

    如果查询太多,您可以替换它从这样的ResourceBundle加载它们。 question

    我希望这有帮助。

        2
  •  2
  •   cletus    16 年前

    Ibatis 很擅长这个。

    <select id="queryName" parameterClass="com.blah.X"><!<[CDATA[
      SELECT z
      FROM a
      JOIN b ON a.id = b.foreign_key
      WHERE
    
      <isNotNull property="value">
        x > y
      </isNotNull>
    
      <isNull property="value">
        x <= y
      </isNull>
    
    ]]></select>
    

    这只是伊巴提斯所能做的一小部分,但它非常轻。技术卓越。

        3
  •  1
  •   Bill Karwin    16 年前

    这不是正确使用准备好的语句参数。参数只能用于代替SQL表达式中的文字值。不是表名、列名或其他SQL语法。

    您可以使用一些库来构建部分SQL查询。我用PHP编写了一个这样的库,名为 Zend_Db_Select .

    编辑: 我在Google上搜索了一个类似Java的库,我发现这个选项可能有帮助:

    • Squiggle 是一个用于动态生成SQL SELECT语句的Java小库。[its]最适合需要构建复杂查询的应用程序,这些查询的条件在运行时会发生变化。通常,弄清楚如何构建这个字符串会非常痛苦。扭动可以消除大部分的疼痛。

    它是免费的,并且在Apache许可证下提供,这是一个相当灵活的开源许可证。

    Google为“Java查询生成器”找到了许多其他选项,但有些不是免费的。有些是可视化查询生成器,而不是程序化查询生成器。

    另一种选择是使用一个复杂的对象关系映射框架,比如Hibernate,但对于您当前的任务来说,这似乎是多余的。

        4
  •  0
  •   Community CDub    8 年前

    Here is similar question

    简短的回答-没有最好的方法。你可能最终会得到这样的结果:

    String selectQuery =
      (new SelectQuery())
      .addColumns(t1Col1, t1Col2, t2Col1)
      .addJoin(SelectQuery.JoinType.INNER_JOIN, joinOfT1AndT2)
      .addOrderings(t1Col1)
      .validate().toString();
    

    但对我来说更糟。

        5
  •  0
  •   Steve B.    16 年前

    我想一方面有一个纯粹的对象方法,如果你试图理解遗留代码,它可能不会对你有很大的帮助。我发现,在重构真正令人讨厌的遗留代码而不是追求“完美”的过程中,通常会更好、更容易地简化小部分,模块化和文档化,因为您可以在不立即重写整个应用程序的情况下制作它们。我发现重构坏代码的最大障碍是,如果我采取太大的步骤,我就不能再相信我没有破坏任何东西——如果有那么糟糕,就可能没有单元测试,而且可能有未定义或未记录的行为。

    我至少会把逻辑和SQL作为第一个步骤进行分解。你不想要的是这样的东西:

    String sql = "yadda yadda yadda ? yadda yadda WHERE ";
    if (mystery condition 1){
       sql = sql + " page=?"
    }
    else if (mystery condition 2)
    {
     sql = sql + " ORDER BY ? "
    }
    

    过了一段时间,你就不知道正在构建什么语句了。不值得保存复制初始SQL的部分。可能更容易理解为:

    private static final String FIND_PAGE_QUERY = "...."
    private static final String ORDER_BY_QUERY =" ..."
    
    if (mystery condition 1){
       return process(FIND_PAGE_QUERY, parameters);
    }
    else if (mystery condition 2)
    {
      return process(ORDER_BY_QUERY, parameters);
    }
    

    然后创建一些东西来包装您的查询和传递的参数 Spring JDBC Row Mappers 或者类似的东西。这仍然很难看,但是作为一个增量步骤,很容易做到,至少可以解决一些查询生成的混乱。

        6
  •  0
  •   Dave Costa    16 年前

    另一种方法是将条件移入SQL语句本身,这样您只需要一条语句。它应该是这样的:

    SELECT z WHERE (? IS NOT NULL AND x > y) OR (? IS NULL AND x <= y)
    

    然后为参数绑定适当的值。

    不确定这是最好的方法…人们可能会发现代码不太清楚。但这是一种可能性。