【问题标题】:Looking for a way to create dynamic SQL from a given SQL Query in Java寻找一种从 Java 中的给定 SQL 查询创建动态 SQL 的方法
【发布时间】:2011-08-30 02:02:21
【问题描述】:

作为工作流引擎的一部分,我正在实现一个通用的 DB 步骤,它将执行任何给定的 SQL 查询并将结果作为 XML 返回。此工作流可以动态配置,因此传递给执行层的查询将是完全限定的静态 SQL 查询,例如,

SELECT * FROM USER WHERE USERID = 10
。这种方法的缺点是数据库每次运行时都会编译查询。有没有一种方法可以以编程方式从查询中创建动态 SQL 查询。 Java 或 Hibernate 之类的 JPA 是否支持此类功能?

【问题讨论】:

标签: java sql hibernate dynamic


【解决方案1】:

我同意用户 kuriouscoder 的观点,即您应该使用绑定变量。这适用于纯 JDBC。大多数 RDBMS 都有一个游标缓存,如果查询相同(即没有内联变量),它会将查询的解析版本和执行计划保存在内存中。所以解析器的开销将是最小的。

就 XML 输出而言,我可以推荐 jOOQ(我是它的开发者)。在即将发布的 1.6.2 版本中,我将为各种格式(XML、HTML、JSON、CSV)添加导出功能。您的查询将使用 jOOQ 的 fluent API 构建,如下所示:

String xml = create.selectFrom(USER)
                   .where(USERID.equal(10))
                   .fetch()
                   .formatXML();

输出将如下所示(并且可以将 XSL 转换为任何其他格式):

<result>
  <fields>
    <field name="USERID"/>
    <field name="FIRSTNAME"/>
    <field name="LASTNAME"/>
    ...
  </fields>
  <records>
    <record>
      <value field="USERID">1</value>
      <value field="FIRSTNAME">Lukas</value>
      <value field="LASTNAME">Eder</value>
      ...
    </record>
    ...
  </records>
</result>

更多详情请见http://www.jooq.org

【讨论】:

    【解决方案2】:

    我在一个项目中使用了 MyBatis 以获得非常相似的行为。 还请查看User Guide 以获取完整信息。

    在 MyBatis 中,您可以使用动态 SQL 定义查询;您可以将包含属性(例如 POJO 或 Map)的对象传递给 SqlMapClient,并在查询文本中将它们用作:

    • #parameters#(类似于 PreparedStatements 中的 ?)
    • $variables$ 直接成为 SQL 字符串的一部分
    • 动态 SQL 功能可根据属性值包含部分 SQL

    然后您的 SQL 映射器将执行查询并返回一个 Java 对象:如果您从查询返回的记录是已知的,您可以将列映射到 POJO;否则在 MyBatis 中,您可以将 HashMap 作为结果类,并最终通过 SqlMapClient 的 queryWithRowHandler() 方法使用处理程序处理每条记录,以发布处理返回的数据。

    一旦您至少拥有查询的 HashMap 表示形式,您就可以轻松地将其转换为 XML。

    【讨论】:

      【解决方案3】:

      通常,您需要使用绑定变量参数化查询模板的输入。有两种形式的绑定变量,即,i) 未命名的绑定变量(或位置绑定变量); ii) 命名绑定变量。

      这可以通过普通 JDBC 完成。我发现 Spring JDBC 特别容易操作。具体看一下 JDBCTemplate 接口及其实现

      【讨论】:

      • 如果我知道查询模板编译时间,我可以对查询进行参数化。就我而言,我只会得到一个包含所有变量集的完整查询。如何从填充的查询中提取模板?打个比方,想象一下我正在为数据库编写 GUI,用户可以执行任何随机查询,但大多数情况下查询是重复的,这留下了优化的机会。
      • 要求是当我得到一个输入查询“SELECT * FROM USER WHERE USER_ID = 10”时,我应该能够生成一个准备好的语句“SELECT * FROM USER WHERE USER_ID = ?”并确定我需要将第一个位置的参数设置为整​​数类型的 10。
      • 如果只是你提到的一种情况,那就去字符串解析。如果你想让它对任何查询都通用,你需要用你自己的 SQL 语法实现解析器
      【解决方案4】:

      如果我明白你在问什么,那么你应该看看 Empiredb http://incubator.apache.org/empire-db/ - 这是一个相当小的项目,但至少在我使用它时,它得到了积极和有益的支持。它就像 python 的 sqlalchemy,因为它允许您使用语言中的类和函数构造 sql 查询。

      引用链接:

      类型安全、无字符串且直观的 API。构建任何 SQL 语句,包括 select 子句,并将其与任何 POJO 一起使用,而不仅仅是功能齐全的实体 bean。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-07-04
        • 2013-09-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-21
        相关资源
        最近更新 更多