Hibernate,iBatis,Java EE或其他Java ORM工具


67

我们正在计划大型的企业应用程序。在经历了J2EE的痛苦之后,我们将重点放在评估休眠状态上。

新的Java EE API看起来更简单。我还阅读了一些有关Hibernate和iBatis的好东西。我们的团队对任何框架都缺乏经验。

我想确定5个主要比较点

  • 学习曲线/易用性
  • 生产率
  • 可维护性/稳定性
  • 性能/可伸缩性
  • 轻松排除故障

如果您要管理一个由约2名J2EE经验的开发人员组成的团队,那么您将使用哪种ORM工具,为什么呢?

Answers:


112

让我对此有所了解。首先,我在使用ORM或纯SQL编写了有关此主题的文章。专门针对您的观点:

学习曲线/易用性

Ibatis与SQL有关。如果您知道SQL,则ibatis的学习曲线很简单。Ibatis在SQL之上做一些事情,例如:

  • 通过...分组;
  • 区分类型;和
  • 动态SQL。

您仍然需要学习,但是最大的障碍是SQL。

另一方面,JPA(包括Hibernate)试图与SQL保持距离,并以对象而非关系的方式呈现事物。正如Joel指出的那样,抽象是泄漏的,JPA也不例外。要执行JPA,您仍然需要了解关系模型,SQL,查询的性能调整等。

Ibatis只会让您应用您知道或正在学习的SQL,而JPA则需要您了解其他内容:如何配置它(XML或注释)。我的意思是弄清楚外键关系是某种类型的关系(一对一,一对多或多对多),类型映射等。

如果您知道SQL,我会说学习JPA的障碍实际上更高。如果您不这样做,那么它与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,适用于MySQL的Navicat中运行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 2014年

也许Oracle Analytics(分析)可以更好地与iBATIS集成(我不知道吗?),但是现在大多数Java容器/服务器都对JPA提供了开箱即用的支持,所以我想说它是更“标准的”,而不是相反。因此,从某种意义上说,它是轻量的,至少它具有广泛的依赖性。
2014年

@ jm0我认为JPA有一个缺点,因为当应用程序服务器提供这些库时,您很容易遇到版本冲突。
延斯·肖德

是的,公平地说,我只提到方面,因为我的公司曾经不鼓励使用lib包含,而赞成使用应用服务器默认值。从那以后,我将所有工作都切换到了Hibernate JPA,发现它更具可移植性/功能。不过,我并没有遇到与应用程序容器发生冲突的问题,这并不是真正的问题……再来看一遍,我不得不做几个项目,这些项目需要在JPA中使用字符串构建本机查询,而且确实很简单+灵活。我希望现在可以对所有内容建模,并且仅使用条件查询。它们对于动态SQL具有惊人的智能。
jm0

11

iBatis和Hibernate之间的一条简单的经验法则是,如果您想要更多的SQL /关系视图,则iBatis更适合;而且对于更复杂的继承链,以及对SQL的直接访问,Hibernate的访问较少。两者都被广泛使用并且是可靠的良好框架。因此,我认为两者都可能会很好地工作。也许阅读两者的教程,看看一个听起来是否比另一个更好,然后选择一个。

在您列出的所有内容中,我认为性能并没有很大不同-瓶颈几乎总是将是数据库,而不是框架。对于其他事情,我认为不同的开发人员会更喜欢一个或另一个,即没有普遍接受的优先级(对于iBatis和Hibernate)。


7

您选择哪种解决方案还取决于您选择(或要求)与Java EE规范的兼容性。JPA是Java EE系统中数据访问的“标准”,因此,如果您坚持遵守此标准,则应该使用它(有一些警告)。

JPA是对象关系映射系统的标准化。因此,它没有提供实现,只是定义了一种标准化方法。Hibernate Entity Manager就是这样一种实现。

由于JPA是跨多个供应商的标准,并且它仍然是相当新的,因此它缺少一些更深奥的功能,这些功能在某些用例中很有价值(例如,用于生成动态SQL的Criteria API)。如果您在需要直接使用Hibernate甚至直​​接使用JDBC的情况下使用JPA计划。对于这种情况,通用的DAO模式非常有用。您可以修改以下内容:非常容易在JPA和JDBC中使用的通用数据访问对象

JPA有一些困难的限制(特别是如果您习惯使用Hibernate),并且对您强加了某些方法,这些方法对于更习惯于编写直接JDBC的开发人员来说是困难的。如果您拥护这种方法,请务必对ORM与JDBC的优缺点做功课。

如果您使用JPA,一旦达到学习曲线,它将在简单的开发方面取得回报(特别是如果您正确地实现了上述DAO模式),而且还将获得查询结果的多层缓存。如果做得好(我知道这是一个很大的“如果”),我已经看到这样做可以带来很多好处。

最后,如果您使用的旧数据模型缺乏灵活性,那么Hibernate(和JPA)将给您带来更多的麻烦,而不是值得的。例如:

  • 如果数据库没有候选主键(用于有效的hashCode和equals实现),则需要对哪些列唯一地定义行进行前期分析-可能很简单,也可能很复杂,具体取决于架构的复杂度;
  • 如果您无法添加版本或时间戳列,则会失去Hibernate进行乐观锁定的能力,最终不得不在更新之前进行查询。

(为响应第一条评论而添加) 如果您幸运地重新设计了数据库,那么在要使用ORM时,有两个非常重要的注意事项:

  • 将版本号列添加到所有相关表以支持乐观锁定。
  • 在数据分析期间,请确定开发人员应为&使用的不可为空的“替代键”列。在那些方法中不要使用PK列。hashCode()equals()

谢谢,这是一些好处。我们正在重新构建应用程序和数据模型,因此在以前的数据模型和遗留系统功能的影响下,它是“相当”新的领域。我希望现在就决定使用ORM工具,以免数据模型过于复杂。
凯文·威廉姆斯

为了回应您的评论,我在上面添加了几点。
爱德华·Q·布里奇斯

6

要将另一个选项添加到列表中,请看:

Ebean ORM(http://ebean-orm.github.io)。

它的主要主张是比JPA或Hibernate更简单,更直观的编程模型。具体来说,它没有Hibernate Session或JPA EntityManager,没有分离/附加的对象(没有合并,持久化,刷新),延迟加载也可以。

...也更容易使用和理解。

您还可以将自己的SQL与Ebean结合使用(用于查询,更新,存储过程),并且IMO与Ibatis匹配,从而可以使用您自己的SQL轻松使用。

如果您希望在Java SE中使用ORM,那么建议您将其检出。

  • LGPL许可证
  • 使用JPA注释进行映射(@ Entity,@ OneToMany等)
  • 无会话的API(不合并,保留,刷新... save()和delete()代替)
  • “部分对象”支持
  • 大型查询支持(每个对象图持久性上下文)
  • 后台查询
  • 对批处理的良好支持
  • 自动查询调整(通过“自动提取”)

干杯,罗布。


谢谢你的建议。我一定会看看。
Kevin Williams

1
有人知道真实的基于Ebean的项目吗?这似乎很有趣,我想看看它与通常的ORM框架相比如何。
路易斯·索埃罗

5

我们目前正在研究一个同时使用Hibernate和ibatis的项目。为什么要使用休眠模式?它支持我们的域模型,关系和继承。我们有一个非常复杂的域模型,hiberante很好地支持它。无需担心编写插入,更新等问题。Ibatis仅用于查看。有查询,我们有与查询映射的视图对象(类似于域模型,但没有域模型)。Ibatis在所需的视图对象中返回数据,而不必担心从结果集中读取数据,而该结果集必须在Spring JDBC中进行管理。为什么我们不使用HQl或Spring JDBC?这个领域是如此复杂,在渲染view时,我们进行计算,分组和大量本机SQL函数。我们在查询中进行所有操作,使用动态查询,在ibatis中管理条件并获得干净的轻量对象。如果您必须遍历多层才能在休眠状态下获取数据,则更有意义。因此,根据您的情况,您可能只想使用一个,或者两者都使用,也可以不使用。但是绝对可以,休眠不是您不能没有的生活。


这是@vsingh的有趣用法。感谢分享。
凯文·威廉姆斯

4

请注意,在非平凡的多线程应用程序中使用JPA / Hibernate(以及大多数其他ORM解决方案)可以很快成为真正的PITA,因为数据库会话需要严格限制在一个线程内(Session对象不是线程安全的)。添加延迟加载和持久性实体最多只能属于一个活动会话这一事实...您将一路狂奔...

您可能想看一看在*多线程* Swing应用程序中使用Hibernate进行会话管理(或仅搜索“休眠多线程”)。

我的经验法则(YMMV):如果应用程序不适合某些请求/响应周期(例如Web服务),则使用其他方法可能会更好。

当然,另一种解决方案是以一种避免提到的框架限制的方式设计应用程序。更改应用程序的设计,使我可以使XYZ框架正常工作,但留下了不好的回味。

无论如何,只要$ 0.02


感谢您的回答。我们主要进行请求/响应类型的工作,但是也有一些多线程组件也可以使用某些功能。我很好奇,当您说“使用其他东西可能会更好”时,您有什么建议吗?
凯文·威廉姆斯

抱歉,恐怕不是(但是我也很想听听建议;)。延迟加载问题的可能解决方案:如果您已经在使用Spring,则可以使用Spring AOP使用HibernateInterceptor(jroller.com/kbaum/entry/orm_lazy_initialization_with_dao)将所有(业务逻辑)方法包装在延迟加载的代码路径中。 。这应该适用于所有需要某种“会话”的ORM框架(我认为也有一个Spring iBatis拦截器,因此Spring可以立即支持至少Hibernate和iBatis)。
JavaGuy 2010年

4

我认为我们应该考虑使用Java(或OO)的主要原因。

该系统必须具有灵活性,并允许不断修改规格(这在现实生活中经常发生)。否则,我们应该使用C编程,因为它要快得多。

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

JSF还比纯JSP / Servlet慢,但开发速度更快。JPA并非在所有情况下都能很好地工作,但是它涵盖了大多数情况,它还允许您插入本机查询而不是JPQL,而无需更改任何代码。但是,如果您发现自己编写了太多本机查询,那么您的项目可能更适合iBatis。

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



至于性能,如果您了解事物如何转换为SQL,并且让它执行他最擅长的事情,或者让JPA做他不满意的事情,那么JPA也会很有效,它将产生过多的查询。没有魔法!您必须了解所生成的查询,而不是盲目希望在某些复杂情况出现时可以采取简单的方法。

同样,如果开发人员拥有SQL的全部功能,他们将编写过于复杂的查询以处理业务逻辑,而不是将其放在一个集中的位置,您将在SQL中拥有一些业务逻辑,而在EJB中则具有一些业务逻辑。JPA应该用于持久化模型,而不是用于业务逻辑。

条件查询也不适合构建安全的nomatterhowcomplex动态查询。


3

如果您确实有一个未开发的项目,则可以使用休眠模式,但是要知道学习曲线相当陡峭。

如果您有一个现有的数据库,那么使用iBatis会更好,因为一天后您会变得富有成效,而两天后您就可以了解所有信息。

您必须考虑的一件事是,休眠条件api非常适合创建自定义查询,这可能取决于您的应用程序,这取决于您的应用程序。


2

如果您没有好的对象模型,那么我将看不到Hibernate的好处。因为您有关系数据库,所以您在ORM中肯定有“关系”,但是“对象”是关键。没有对象,没有ORM。我认为对象和表之间的1:1映射(没有更丰富的对象行为)不能证明ORM是正确的。如果您遇到这种情况,请坚持使用JDBC或iBatis。


我们正在努力建立一个具有持久层的强大对象模型,以从业务逻辑和视图中封装ORM,以便在需要时可以交换/混合/优化ORM而不会产生过多影响,同时保持堆栈的可维护性。不引入过多的复杂性。
凯文·威廉姆斯

流行语宾果游戏-您赢了!您正在引入复杂性,并且一定会产生一定的影响,这只是您认为“过度”的问题。
duffymo

2

我建议您使用JPA,并(很大程度上取决于)项目的持续时间/范围,您不妨研究一下JPA2,因为它提供了JPA的某些缺少的功能(例如,非常好的Query API)。


谢谢,没想到。您有使用JPA的经验吗?您可以分享的痛苦/收获?
凯文·威廉姆斯

1

休眠。您的项目肯定会在以后变得更大,并且投资(学习休眠)将以一种或另一种方式获得回报。


但是,为什么它比iBatis或其他解决方案更好?
凯文·威廉姆斯

不好了 我的工作水平更高,可能会更困难,而且绝对更完善。
cherouvim

-2

在决定使用哪个工具之前,您是否尝试过回答为什么甚至使用ORM工具?如果您的团队中有一些了解SQL的人,请参阅JDBC。


我们通常在sql方面很“擅长”,但是我敢肯定,其中的一种工具会比编写一堆SQL和连接管理代码提供一定程度的自动CRUD实现。
凯文·威廉姆斯

这是一个典型的答案。人们把它当作是理所当然的,但是我还没有看到一些强有力的论据证明这一点。这是我与一堆意见的类似主题的博客文章:yakovfain.javadevelopersjournal.com/...
雅科夫费恩

您的链接不是很令人信服。似乎您错过了Valery提出的要点。
爱德华·Q·布里奇斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.