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

发布于 2024-07-10 21:12:19 字数 455 浏览 6 评论 0原文

我有几个实例,其中一部分旧版 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,我目前没有使用库的选择。

I have several instances where that a section of legacy sql statements is based on a dependency. for example.

if (x !=null)
{
  SQL = "SELECT z WHERE x > y";
}
else
{
  SQL = "SELECT z WHERE x <= y";
} 

SQL2 = SQL + " JOIN a ON b";

I am creating PreparedStatements out of this legacy code. What is the best-practice here. Should I create a PreparedStatement for the var SQL and nest it inside of SQL2 of should there be multiple PreparedStatements based on SQL2 without nesting, or something totlly different?

The code is much more complex than the example, as the SQL var is reused inside many long and complex SQL queries.

EDIT: Project Design requires using PreparedStatements, I don't have the choice of using libraries at this moment.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

风渺 2024-07-17 21:12:19

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

>或者是否应该有多个基于 SQL2 且不嵌套的PreparedStatement

此外:如果您可以为每个查询创建一个字符串,这样会更好。 我真的不喜欢将 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 加载它们,如下所示 问题

我希望这有帮助。

>Should I create a PreparedStatement for the var SQL and nest it inside of SQL2

No

>Or should there be multiple PreparedStatements based on SQL2 without nesting

Yes

Furthermore: If you could create one string per query that would be better. I don't really like to mix SQL with code. It makes it harder to debug and to understand, you can't copy/paste to a SQL tool to test it easily. By separating the SQL from your code you'll isolate your query from the operation ( the actual fetch ) and it would be easier to maintain. Plus if the code is not yours it will be a lot easier to understand.

It doesn't matter it looks like your're repeating strings, the point would be to simplify the statements as much as possible.

I would do something like this:

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";
 }

And then use it from your class:

 PreparedStatement pstmt = getCon().prepareStatement( getQuery() );


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

While creating the class "DatabaseQueries" you'll find you're repeating a lot of strings, I think it would be fine to susbtitute some part with other constants.

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 ;

}

The point here is to make things simpler. This is the first step. In a second step you can create a class to create those queries that are really really complex, but probably YAGNI.

If the queries are too much you can replace it to load them from a ResourceBundle like in this question

I hope this helps.

嘿咻 2024-07-17 21:12:19

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 功能的一小部分,但它非常轻量级。 技术精湛。

Ibatis is very good at this.

<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>

This is but a small fraction of what Ibatis can do but its extremely lightweight. Excellent technology.

秋日私语 2024-07-17 21:12:19

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

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

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

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

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

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

另一种选择是使用复杂的对象关系映射框架(如 Hibernate),但这对于您当前的任务来说似乎有些过分了。

This is not the proper use of prepared statement parameters. Parameters can be used only in place of a literal value in an SQL expression. Not table names, column names, or other SQL syntax.

You could use some library for building parts of an SQL query. I worked on a library like this in PHP, called Zend_Db_Select.

edit: I googled a bit for a similar library for Java, and I found this option which may be helpful:

  • Squiggle is a little Java library for dynamically generating SQL SELECT statements. [Its] sweet spot is for applications that need to build up complicated queries with criteria that changes at runtime. Ordinarily it can be quite painful to figure out how to build this string. Squiggle takes much of this pain away.

It's free and offered under the Apache License, which is a pretty flexible open-source license.

Googling for "java query builder" found a number of other options, but some were not free. Some were visual query builders, not programmatic query builders.

Another option is to use a complicated object-relational mapping framework like Hibernate, but this seems overkill for your current task.

人心善变 2024-07-17 21:12:19

这是类似的问题

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

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

但对我来说,情况更糟。

Here is similar question

Short answer - there is no best way. You may end up with something like this:

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

But to me it is even worse.

不必了 2024-07-17 21:12:19

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

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

I guess on one hand there's a purist object approach, which is probably not going to be terribly helpful to you if you're trying to make sense of legacy code. I've found that in refactoring really nasty legacy code rather than striving for "perfect" it's often better, and easier, to simplify small pieces, as modular and well documented as you can make them without rewriting the entire app at once. I've found that the biggest hurdle for me in refactoring bad code is that if I take too large steps I can't any longer be confident that I haven't broken anything - if it's that bad, there are probably no unit tests, and there's likely undefined or undocumented behavior.

I'd at least break out the logic and the sql as a first pass. The thing you don't want is something like this:

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

After a while you won't be able to tell what statements are being built. It's not worth saving the bit of duplicating the initial sql. It might be easier to understand as :

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);
}

and then just create something to wrap your queries and parameters passed like Spring JDBC Row Mappers or something similar. This is still ugly, but it's easy to do as an incremental step from what you've got, and will at least sort out some of the confusion of query generation.

梦在深巷 2024-07-17 21:12:19

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

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

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

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

Another approach would be to move the conditional into the SQL statement itself so you only need one statement. It would be something like:

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

and then bind an appropriate value for the parameter.

Not sure it's the best approach ... people might find the code less clear. But it is a possibility.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文