1

我有几个实例,其中一部分遗留 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 var 在许多长而复杂的 SQL 查询中重复使用。

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

4

6 回答 6

4

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

> 还是应该有多个基于SQL2的PreparedStatement没有嵌套

是的

此外:如果您可以为每个查询创建一个字符串,那就更好了。我不太喜欢将 SQL 与代码混合使用。它使调试和理解变得更加困难,您无法复制/粘贴到 SQL 工具来轻松对其进行测试。通过将 SQL 从代码中分离出来,您可以将查询与操作(实际的 fetch )隔离开来,并且更容易维护。另外,如果代码不是你的,它会更容易理解。

看起来你在重复字符串并不重要,重点是尽可能简化语句。

我会做这样的事情:

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 加载它们,就像在这个 问题中一样

我希望这有帮助。

于 2008-12-22T22:37:07.723 回答
2

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>

这只是 Ibatis 可以做的一小部分,但它非常轻量级。优秀的技术。

于 2008-12-22T22:33:41.600 回答
1

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

您可以使用一些库来构建 SQL 查询的一部分。我在 PHP 中开发了一个类似的库,名为Zend_Db_Select.

编辑:我用谷歌搜索了一个类似的 Java 库,我发现这个选项可能会有所帮助:

  • Squiggle是一个用于动态生成 SQL SELECT 语句的小型 Java 库。[它的] 甜蜜点适用于需要使用在运行时更改的标准来构建复杂查询的应用程序。通常,弄清楚如何构建此字符串可能会非常痛苦。Squiggle 消除了这种痛苦。

它是免费的,根据 Apache 许可证提供,这是一个非常灵活的开源许可证。

谷歌搜索“java query builder”发现了许多其他选项,但有些不是免费的。有些是可视化查询构建器,而不是程序化查询构建器。

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

于 2008-12-22T22:17:16.907 回答
0

这是类似的问题

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

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

但对我来说,情况更糟。

于 2008-12-22T22:31:19.250 回答
0

我想一方面有一种纯粹的对象方法,如果你试图理解遗留代码,这可能对你没有太大帮助。我发现在重构真正令人讨厌的遗留代码而不是力求“完美”时,简化小块通常更好、更容易,尽可能模块化和有据可查,而无需一次重写整个应用程序。我发现重构糟糕代码的最大障碍是,如果我采取的步骤太大,我就不能再确信我没有破坏任何东西——如果它那么糟糕,可能没有单元测试,并且可能存在未定义或未记录的行为。

我至少会打破逻辑和 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 或类似的东西。这仍然很丑陋,但是作为您所拥有的增量步骤很容易做到,并且至少可以解决查询生成的一些混乱。

于 2008-12-22T22:32:16.627 回答
0

另一种方法是将条件移动到 SQL 语句本身,这样您只需要一个语句。它会是这样的:

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

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

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

于 2008-12-23T14:32:07.453 回答