【问题标题】:ORM Technologies vs JDBC?ORM 技术与 JDBC?
【发布时间】:2009-10-16 00:00:15
【问题描述】:

我的问题是关于 ORM 和 JDBC 技术,与 JDBC 和其他方式相比,您决定采用 ORM 技术的标准是什么?

谢谢。

【问题讨论】:

    标签: java orm jdbc database-connection


    【解决方案1】:

    JDBC

    1. 使用 JDBC,开发人员必须编写代码来将对象模型的数据表示映射到关系数据模型及其对应的数据库架构。
    2. 使用 JDBC,Java 对象与数据库表的自动映射以及反之转换将由开发人员通过代码行手动处理。
    3. JDBC 仅支持本机结构化查询语言 (SQL)。开发人员必须找出访问数据库的有效方法,即从多个查询中选择有效的查询来执行相同的任务。
    4. 使用 JDBC 处理具有大量数据库特定代码的持久数据(数据库表)的应用程序。将表数据映射到应用程序对象(反之亦然)所编写的代码实际上是将表字段映射到对象属性。随着表更改或数据库更改,必须更改对象结构以及更改为映射表到对象/对象到表而编写的代码。
    5. 使用 JDBC,开发人员有责任处理 JDBC 结果集并通过代码将其转换为 Java 对象,以便在应用程序中使用这些持久数据。因此,使用 JDBC,Java 对象和数据库表之间的映射是手动完成的。
    6. 使用 JDBC,缓存是通过手动编码来维护的。
    7. 在 JDBC 中,没有检查是否总是每个用户都有更新的数据。此检查必须由开发人员添加。

    休眠。

    1. Hibernate 是一种灵活而强大的 ORM 解决方案,用于将 Java 类映射到数据库表。 Hibernate 本身使用 XML 文件处理这种映射,因此开发人员不需要为此编写代码。
    2. Hibernate 提供透明的持久性,开发人员在与 RDBMS 交互期间无需显式编写代码来将数据库表元组映射到应用程序对象。
    3. Hibernate 提供了一种功能强大的查询语言 Hibernate 查询语言(独立于数据库类型),它以熟悉的 SQL 类语法表示,并且包括对多态查询的完全支持。 Hibernate 还支持原生 SQL 语句。它还选择了一种有效的方式来为应用程序执行数据库操作任务。
    4. Hibernate 自己提供此映射。表和应用程序对象之间的实际映射是在 XML 文件中完成的。如果数据库或任何表中发生更改,则只需更改 XML 文件属性。
    5. Hibernate 通过自己维护对象表映射来减少代码行数,并将结果以 Java 对象的形式返回给应用程序。它使程序员从手动处理持久数据中解脱出来,从而减少了开发时间和维护成本。
    6. 休眠,具有透明持久性,缓存设置为应用程序工作空间。作为查询的结果,关系元组被移动到这个缓存中。如果客户端应用程序为相同的写入多次读取相同的数据,它会提高性能。自动透明持久性允许开发人员更多地关注业务逻辑而不是此应用程序代码。
    7. Hibernate 使开发人员能够为应用程序定义版本类型字段,由于这个定义的字段,Hibernate 会在每次关系元组以 Java 类对象的形式更新到该表时更新数据库表的版本字段。因此,如果两个用户检索相同的元组然后对其进行修改,并且一个用户将修改后的元组保存到数据库中,Hibernate 会自动更新此元组的版本。当其他用户尝试将更新的元组保存到数据库时,它不允许保存它,因为该用户没有更新的数据。

    【讨论】:

      【解决方案2】:

      复杂性。

      ORM如果您的应用程序是域驱动的并且对象之间的关系很复杂,或者您需要让此对象定义应用程序的功能。

      JDBC/SQL 如果您的应用程序足够简单,可以直接从数据库中呈现数据,或者它们之间的关系足够简单。

      Martin Fowler 的《企业应用程序架构模式》一书更好地解释了这两种类型之间的区别:

      请参阅:Domain ModelTransaction Script

      【讨论】:

      • +1。我自己的说法是,您必须了解 ORM 的大量恒定成本何时“为自己买单”。
      • 我必须同意这一点 - 但我还要补充一点,有时在单个应用程序中同时使用两者是有意义的。
      • ...如果您的应用程序如此复杂以至于 ORM 是合理的,架构师应该真正质疑是否有更好的方法来分解应用程序(提示:微服务)。
      【解决方案3】:

      我想你忘了看“函数关系映射”

      总结如下:

      • 如果您想专注于数据结构,请使用 JPA/Hibernate 等 ORM
      • 如果您想了解治疗方法,请查看 FRM 库:QueryDSL 或 Jooq
      • 如果您需要针对特定​​数据库调整 SQL 请求,请使用 JDBC 和本机 SQL 请求

      各种“关系映射”技术的优势在于可移植性:您可以确保您的应用程序可以在大多数 ACID 数据库上运行。 否则,您将在手动编写 SQL 请求时应对各种 SQL 方言之间的差异。

      当然你可以限制自己使用 SQL92 标准(然后做一些函数式编程),或者你可以在 ORM 框架中重用函数式编程的一些概念

      ORM 的优势是建立在会话对象之上的,会话对象可能会成为瓶颈:

      1. 只要底层数据库事务正在运行,它就会管理对象的生命周期。
      2. 它维护 Java 对象和数据库行之间的一对一映射(并使用内部缓存来避免重复对象)。
      3. 它会自动检测关联更新和要删除的孤立对象
      4. 它使用乐观或悲观锁处理并发问题。

      然而,它的优点也是它的缺点:

      1. 会话必须能够比较对象,因此您需要实现 equals/hashCode 方法 但是对象相等性必须植根于“业务密钥”而不是数据库 ID(新的瞬态对象没有数据库 ID!)。 但是,一些具体化的概念没有业务平等(例如操作)。 一种常见的解决方法依赖于 GUID,这往往会使数据库管理员感到不安。

      2. 会话必须监视关系更改,但其映射规则会推动使用不适合业务算法的集合。 有时您想使用 HashMap 但 ORM 将要求密钥是另一个“富域对象”而不是另一个轻量级对象...... 然后你必须在作为键的富域对象上实现对象相等...... 但是你不能,因为这个对象在商业世界中没有对应物。 所以你回到一个简单的列表,你必须迭代(和性能问题导致)

      3. ORM API 有时不适合实际使用。 例如,现实世界的 Web 应用程序尝试通过在您获取数据时添加一些“WHERE”子句来强制执行会话隔离...... 那么“Session.get(id)”就不够用了,你需要转向更复杂的DSL(HSQL、Criteria API)或者回到原生SQL

      4. 数据库对象与专用于其他框架的其他对象发生冲突(例如 OXM 框架 = 对象/XML 映射)。 例如,如果您的 REST 服务使用 jackson 库来序列化业务对象。 但是这个杰克逊正好映射到一个冬眠者。 然后你要么合并两者,你的 API 和数据库之间就会出现强耦合 或者你必须实现一个翻译,你从 ORM 中保存的所有代码都丢失了......

      另一方面,FRM 是“对象关系映射”(ORM) 和原生 SQL 查询(使用 JDBC)之间的权衡

      解释 FRM 和 ORM 之间差异的最佳方法是采用 DDD 方法。

      • 对象关系映射支持使用“富域对象”,这是 Java 类,其状态在数据库事务期间是可变的
      • 函数关系映射依赖于不可变的“不良域对象”(以至于每次要更改其内容时都必须克隆一个新对象)

      它释放了对 ORM 会话的约束,并且大部分时间依赖于 SQL 上的 DSL(因此可移植性并不重要) 但另一方面,您必须查看交易细节,并发问题

      List<Person> persons = queryFactory.selectFrom(person)
        .where(
          person.firstName.eq("John"),
          person.lastName.eq("Doe"))
        .fetch();
      

      【讨论】:

        【解决方案4】:

        这也取决于学习曲线。

        Ebean ORM 的学习曲线非常低(简单的 API、简单的查询语言),如果您对 JPA 映射注释(@Entity、@Table、@OneToMany 等)感到满意。

        【讨论】: