Hibernate、iBatis、Java EE或其他Java ORM工具是什么?

67

我们正在规划一款大型企业应用程序。在遭受J2EE痛苦的经历后,我们将精力集中在评估Hibernate上。

看起来新的Java EE API更简单。我也读到了一些关于Hibernate和iBatis的好东西。我们的团队对这些框架都缺乏经验。

我想确定以下5个主要比较点:

  • 学习曲线/易用性
  • 生产力
  • 可维护性/稳定性
  • 性能/可扩展性
  • 故障诊断的易用性

如果您要管理一个有J2EE经验的6人开发团队,您会使用哪种ORM工具?为什么?

12个回答

112
让我试着解决这个问题。首先,我在使用ORM还是纯SQL?这个主题上已经写了一些内容。具体来说,为了回答你的问题:
学习曲线/易用性
Ibatis 关注于 SQL。如果你知道 SQL,那么学习 Ibatis 的难度就很小。Ibatis 在 SQL 上做了一些工作,比如:
  • group by;
  • discriminated types; 和
  • dynamic SQL。
这些你仍需要学习,但最大的障碍是 SQL。
另一方面,JPA(包括 Hibernate)试图与 SQL 保持距离,并以对象而不是关系方式呈现事物。然而,正如 Joel 指出的那样,抽象是有泄露的,JPA 也不例外。要做 JPA,你仍需要了解关系模型、SQL、查询性能调整等相关知识。
当你使用 Ibatis 时,只需要应用你所知道或正在学习的 SQL;而当你使用 JPA 时,你需要知道其他东西:如何配置它(XML 或注释)。我指的是弄清楚外键关系是某种关系(一对一、一对多或多对多),类型映射等等。
如果你知道 SQL,我认为学习 JPA 的门槛实际上更高。如果你不知道 SQL,则结果是参差不齐的,JPA 允许你有效地推迟学习 SQL 的时间(但它不能无限期地推迟)。
使用JPA后,一旦设置好实体及其关系,其他开发人员就可以简单地使用它们,而无需学习有关配置JPA的所有内容。这可能是一个优势,但开发人员仍需要了解实体管理器、事务管理、托管与非托管对象等方面的知识。
值得注意的是,JPA还有自己的查询语言(JPA-SQL),无论你是否了解SQL,都需要学习它。你会发现,在某些情况下,JPA-SQL无法做到SQL所能做的事情。
生产力
这很难判断。个人认为在ibatis中更加高效,但我也非常熟悉SQL。有些人会争辩说他们使用Hibernate更加高效,但这可能部分原因是不熟悉SQL。
此外,JPA的生产力是具有欺骗性的,因为你偶尔会遇到数据模型或查询问题,需要花费半天到一天的时间来解决,你需要打开日志,观察你的JPA提供程序产生的SQL,并找出正确和高效的设置和调用组合,以使其产生正确且高效的结果。
而在Ibatis中,你没有这种问题,因为你自己编写了SQL。你通过在PL/SQL Developer、SQL Server Management Studio、Navicat for MySQL或其他工具中运行SQL来测试它。在查询正确之后,你所做的就是映射输入和输出。
此外,我发现JPA-QL比纯SQL更加笨拙。你需要单独的工具才能运行JPA-QL查询并查看结果,这是你必须学习的额外内容。我实际上发现JPA的整个部分都有些笨拙和难以控制,尽管有些人喜欢它。

可维护性/稳定性

Ibatis的危险在于过度扩张,这意味着你的开发团队可能会根据需要不断添加价值对象和查询,而不是寻找重复使用的机会。相比之下,JPA每个表只有一个实体,一旦拥有该实体,就可以将命名查询放在该实体上,因此很难错过。临时查询仍然可以重复,但我认为这不太可能成为问题。

然而,这是以刚性为代价的。通常,在应用程序中,您需要从不同的表中获取一些数据。对于SQL来说,这很容易,因为您可以编写单个查询(或少量查询)以一次性获取所有数据,并将其放入专门用于此目的的自定义值对象中。

使用JPA,您将该逻辑移动到业务层中。实体基本上是全套或不要。现在这并不严格正确。各种JPA提供程序都允许您部分加载实体等,但即使在那里,您也在谈论相同的离散实体。如果您需要来自4个表的数据,则需要4个实体,或者您需要将所需数据合并到业务或表示层中的某种自定义值对象中。

我喜欢ibatis的另一件事是所有SQL都是外部的(在XML文件中)。有些人会将此视为劣势,但我不会。然后,您可以通过搜索XML文件相对容易地找到表和/或列的用途。对于嵌入在代码中的SQL(或根本没有SQL的情况),可能会更难找到。您还可以将SQL剪切并粘贴到数据库工具中并运行它。多年来,我无法过多强调这有多少次对我有用。

性能/可扩展性

在这里,我认为ibatis毫无疑问是胜者。它是直接的SQL和低成本的。从其本质上讲,JPA简单地无法管理相同级别的延迟或吞吐量。现在,JPA的优势在于延迟和吞吐量只很少出现问题。然而,高性能系统确实存在,并且倾向于不利于像JPA这样更加重量级的解决方案。
此外,使用ibatis,您可以编写一个查询,返回您想要的完全数据和您需要的确切列。基本上,当返回离散实体时,JPA没有任何方法可以击败(甚至匹配)它。
易于故障排除
我认为这对于Ibatis也是一个胜利。就像我上面提到的那样,使用JPA,有时您会花费半天时间来获取查询或实体生成所需的SQL,或者诊断事务失败的问题,因为实体管理器试图持久化未经管理的对象(这可能是批处理作业的一部分,在其中您已经提交了大量工作,因此可能不容易找到)。
如果尝试使用不存在的表或列,则两者都将失败,这很好。
其他标准
现在,您没有将可移植性作为要求之一(意味着在数据库供应商之间移动)。值得注意的是,JPA在这里具有优势。注释不太可移植,例如,Hibernate XML(例如,标准JPA注释没有Hibernate的“本机”ID类型的等效项),但两者都比ibatis / SQL更可移植。
此外,我已经看到JPA / Hibernate被用作便携式DDL的形式,这意味着您运行一个小型Java程序,从JPA配置创建数据库模式。对于ibatis,您将需要每个受支持的数据库的脚本。
移植性的缺点在于,JPA 在某些方面是最低公共分母,这意味着支持的行为在很大程度上是跨多个数据库供应商通用的行为。如果你想在 ibatis 中使用 Oracle Analytics,没有问题。但在 JPA 中呢?那可就有问题了。

我认为这个过分夸大了iBATIS的简单性的独特性,并且淡化了在Java层中具有业务逻辑的价值。本地查询可以从JPA中的文本文件加载和/或作为字符串进行操作 - 这本质上就是iBATIS。在这种意义上,我认为JPA几乎是一个超集。您可以使用本地查询并将其映射到专门设计的实体,或者迁移到JPQL并尝试巩固业务逻辑。 - jm0
也许 Oracle Analytics 与 iBATIS 集成更好(我不确定?),但是大多数 Java 容器/服务器现在都支持 JPA,因此我认为它更“标准”,而不是反过来。因此,至少它是一个广泛可用的依赖项,从而使其具有轻量级的特点。 - jm0
@jm0 我认为这是 JPA 的一个缺点,因为当应用服务器提供这些库时,你很容易遇到版本冲突的问题。 - Jens Schauder
其实我提到这个方面只是因为曾经有一段时间,我的公司鼓励使用应用服务器默认设置而不是包含lib。但是我现在已经全部转向使用Hibernate JPA,并发现它更加便携/功能强大。虽然我没有遇到与应用程序容器的冲突,但这并不是一个真正的问题...重新审视这个问题,我必须做一些需要使用字符串构建JPA本地查询的项目,这非常简单+灵活。尽管我现在更喜欢将所有东西建模并仅使用标准查询。对于动态SQL,它们非常智能。 - jm0

11
一个简单的经验法则是,如果你想要更多关于SQL/关系型世界的视图,那么 iBatis 更加合适;如果你需要更复杂的继承链和更少直接访问 SQL 的视图,则 Hibernate 更加合适。两者都是广泛使用和可靠的好框架。所以我认为两者都能很好地工作。也许可以阅读一些教程,看看哪一个听起来更好,然后选择其中之一。
在你列出的事项中,我认为性能差异并不大——瓶颈几乎总是数据库,而不是框架。对于其他事情,我认为不同的开发人员会更喜欢其中的一个,即没有普遍认可的优先级(iBatis vs Hibernate)。

7
你选择的解决方案也取决于你选择(或被要求)遵守Java EE规范的程度。JPA是Java EE系统中数据访问的“标准”,因此如果你特别注重遵守这一点,应该使用它(但有一些注意事项)。
JPA是对象关系映射系统的标准化。因此,它并不提供实现,只是定义了一种标准化的方法。Hibernate Entity Manager就是其中一种实现。
由于JPA跨越多个供应商的标准,而且它仍然相当新,缺少一些在某些用例中非常有价值的更深奥的功能(例如,用于生成动态SQL的Criteria API)。如果你选择了JPA,则需要计划一些情况,在这些情况下,你需要直接使用Hibernate,甚至是JDBC。对于这种情况,通用DAO模式非常有用;你可以很容易地修改此链接中的内容:通用数据访问对象以在JPA和JDBC中使用。
JPA有一些困难的限制(特别是如果你习惯于Hibernate),并且对你施加了某些方法,这对于那些更习惯于编写直接JDBC的开发人员来说可能很困难。如果您作为一种方法的倡导者,请确保您对ORM与JDBC的优缺点进行功课研究。
如果您选择JPA,一旦您掌握了学习曲线,它将在简单的开发方面(特别是如果您正确实现了上述DAO模式)以及获得查询结果的多层缓存方面得到回报。如果做得好(我知道这是一个大问题),我已经看到它提供了可观的好处。
最后,如果您拥有一个您几乎没有灵活性的遗留数据模型,Hibernate(和JPA)会给您带来比价值更高的头疼。例如:
- 如果数据库没有候选主键(用于有效的hashCode和equals实现),则需要事先分析哪些列唯一定义行——可能简单,也可能复杂,具体取决于模式的复杂性; - 如果无法添加版本或时间戳列,则失去了Hibernate执行乐观锁定的能力,并且最终必须在更新之前进行查询。

(针对第一个评论添加) 如果你足够幸运地重新设计数据库,并且要使用ORM,则有两个非常重要的考虑因素:

  • 在所有相关表中添加版本号列以支持乐观锁定。
  • 在数据分析期间,决定用于hashCode()equals()的非空 "替代键"列,开发人员不应在这些方法中使用PK列。

谢谢,这些是一些很好的观点。我们正在重建应用程序和数据模型,因此它在某种程度上是全新的,但受到先前数据模型和遗留系统能力的影响。我希望现在就决定使用ORM工具,而不是等到数据模型太过复杂。 - Kevin Williams
我已经根据你的评论添加了一些要点。 - Edward Q. Bridges

6
要向列表中添加另一个选项...请查看:
Ebean ORM (http://ebean-orm.github.io)。
它的主要优点是编程模型比JPA或Hibernate更简单、更直观。具体而言,它没有Hibernate Session或JPA EntityManager,没有分离/附加对象(没有merge、persist、flush),懒加载只需一步即可完成。
... 也就是说,更容易使用和理解。
您还可以使用自己的SQL与Ebean配合使用(用于查询、更新、存储过程),在我看来,它与Ibatis在使用自己的SQL方面相当容易使用。
如果您想在Java SE中使用ORM,则建议您尝试一下。
LGPL许可证 使用JPA注释进行映射(@Entity、@OneToMany等) 无会话API(无merge、persist、flush……改为save()和delete()) "部分对象"支持 大型查询支持(每个对象图持久性上下文) 后台查询 良好的批处理支持 自动查询调整(通过"Autofetch")
谢谢,Rob.

感谢您的建议。我一定会仔细研究它。 - Kevin Williams
1
有人知道有基于Ebean的真实项目吗?它似乎很有趣,我想看看它与通常的ORM框架相比如何。 - Luis Soeiro

5
我们目前正在开发一个使用Hibernate和ibatis的项目。 为什么要使用Hibernate? 它支持我们的领域模型、关系和继承。我们有一个非常复杂的领域模型,Hibernate非常好地支持了它。 不需要担心编写插入、更新等操作。 Ibatis仅用于视图。我们有查询和视图对象(类似于领域模型但不是领域模型),这些对象与查询映射。Ibatis返回您想要的视图对象中的数据,无需担心从结果集中读取,这在Spring JDBC中必须管理。 为什么我们不使用HQL或Spring JDBC呢? 该领域非常复杂,当渲染视图时,我们需要计算、分组和大量使用本机SQL函数。我们在查询中完成所有工作,使用动态查询,在ibatis中管理条件并获得一个干净、轻量级的对象。 如果需要遍历多个层次来获取Hibernate中的数据,则更有意义。 因此,根据您的情况,您可能只想使用其中之一、两个或没有。 但绝对不能说Hibernate是您无法离开的东西。

这是一个有趣的用法@vsingh。谢谢分享。 - Kevin Williams

4
请注意,在非平凡的多线程应用程序中使用JPA/Hibernate(以及可能大多数其他ORM解决方案)可能很快变成真正的烦恼,因为数据库会话需要限制在一个线程中(Session对象不是线程安全的)。加上延迟加载和持久实体最多只能属于一个活动会话的事实......你将面临一次可怕的旅程......
你可能想看一下Session management using Hibernate in a *multi-threaded* Swing application(或者只需搜索'hibernate multi-threaded')。
我的经验法则(YMMV):如果应用程序不适合某种请求/响应周期(例如WebService),那么您可能最好使用其他东西。
当然,另一种解决方案是以规避所提到的框架限制的方式设计应用程序。但是,更改应用程序的设计以使框架XYZ工作留下了不良的口感。
无论如何,这只是我的$0.02。

谢谢你的回答。我们主要进行请求/响应类型的工作,但也有一些多线程组件需要改进。我很好奇,当你说“你最好使用其他东西”时,你有什么建议吗? - Kevin Williams
抱歉,我恐怕不行(但我很想听听建议);。懒加载问题的可能解决方案:如果您已经在使用Spring,则可以使用Spring AOP将所有(业务逻辑)方法包装在使用HibernateInterceptor(http://www.jroller.com/kbaum/entry/orm_lazy_initialization_with_dao)的懒加载代码路径中。这对于所有需要某种“会话”的ORM框架都应该有效(我认为Spring iBatis拦截器也是如此,因此至少Hibernate和iBatis受到Spring开箱即用的支持)。 - JavaGuy

4
我认为我们使用Java(或OO)的主要原因是系统必须具有灵活性,并允许规范的不断修改(在现实生活中经常发生)。否则,我们应该使用C进行编程,因为它更快。

我认为Web应用程序的最佳堆栈应该是Java EE:JPA - EJB - JSF(带扩展持久性上下文会话范围)。

JSF也比纯JSP / Servlet慢,但开发速度更快。

JPA学习难度较大,但开发速度更快(您知道:RAD),并且更改不会产生大的(容易出错的复制粘贴)影响。在您最常使用的实体中添加新列,您将不得不更新iBatis中的所有语句...

JPA并非所有情况下都表现良好,但它涵盖了大多数情况,并且还可以让您插入Native Query而无需更改任何代码。但是,如果您发现自己编写太多Native Query,则iBatis可能更适合您的项目。

至于性能,如果您理解事物如何转换为SQL,并且将其放置在最佳位置,那么JPA也很高效。如果您让它执行不舒适的任务,它将生成太多查询。没有什么魔法!您必须了解生成的查询,而不是盲目地希望您可以采取简单的方法来处理某些复杂情况。

此外,如果开发人员具有SQL的所有功能,则会编写过于复杂的查询以处理业务逻辑,而不是将其集中在一个地方,您将在SQL中拥有一些业务逻辑,在EJB中拥有一些业务逻辑。 JPA应用于持久化模型,而不是业务逻辑。

Criteria Query也无法构建安全的nomatterhowcomplex动态查询。

3

如果你确实有一个Greenfield项目,你可以使用Hibernate,但要注意学习曲线非常陡峭。

如果你有一个现有的数据库,那么使用iBatis会更好,因为一天后你就能投入生产,再过两天你就可以了解它的所有内容。

有一件事情需要考虑,那就是Hibernate Criteria API非常适合创建自定义查询,这可能是支持Hibernate的一个很好的理由,具体取决于你的应用程序。


2
如果你没有一个好的对象模型,我不认为使用Hibernate有任何好处。 ORM中的“关系”当然是有的,因为你有一个关系数据库,但是“对象”才是关键。 没有对象,就没有ORM。 我认为如果只有简单的对象和表之间的1:1映射,而没有更丰富的对象行为,那么这种情况下用ORM是不合适的。 如果这是你的情况,请坚持使用JDBC或iBatis。

我们正在努力构建一个强大的对象模型,其中包含一个持久层,以将ORM与业务逻辑和视图封装起来,这样如果需要的话,就可以在不引入过多复杂性的情况下交换/混合/优化ORM,同时保持堆栈的可维护性。 - Kevin Williams
噱头宾果 - 你赢了!你正在引入复杂性,必然会产生一些影响,只是问题在于你认为什么是“过度”的。 - duffymo

2

我建议使用JPA,并且根据您的项目持续时间/范围,您也可以研究一下JPA2,因为它提供了JPA缺失的一些功能(例如非常好用的查询API)。


谢谢,我没有考虑到那个。你有使用JPA的经验吗?有什么痛点/收获可以分享的吗? - Kevin Williams

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接