休眠或JDBC


68

我有一个胖客户端,带有25个表和约15个JInternalFrames(表的数据输入表单)的架构的java swing应用程序。我需要为DBMS交互选择直接的JDBC或ORM(在这种情况下为Spring框架休眠)的设计选择。应用程序的构建将在将来发生。

对于这样规模的项目,冬眠会显得过大吗?对于肯定或否定答案的解释将不胜感激(如果需要,甚至可以采用其他方法)。

TIA。


还有其他可能性。关于iBATIS iBATIS.apache.org
Adrian Pronk,

过度杀伤力?概念过度杀伤力?另一个罐子?
苏里亚2009年

2
我当时想过分地增加额外的处理开销,以增加一个层,维护该层需要额外的开发人员技能(我有这种技能,但是我必须考虑何时不由它来维护),而是耦合到第三方而不是本机(尽管多余的罐子不是AFAIC的问题)。那种东西。
jmq,2009年

6
+1表示良好的提问态度和明确的问题
KLE,2009年

Answers:


186

好问题,没有一个简单的答案。

在多年使用多个项目后,我曾经是Hibernate的忠实拥护者。我曾经相信任何项目都应默认为休眠状态。

今天我不太确定。

Hibernate(和JPA)在某些方面非常有用,尤其是在开发周期的早期。使用Hibernate进行操作要比使用JDBC快得多。您可以免费获得许多功能-缓存,乐观锁定等。

另一方面,它有一些隐性成本。开始时,Hibernate非常简单。遵循一些教程,在您的课程上添加一些注释-您便会拥有持久性。但这并不简单,并且要能够编写出色的代码,需要对它的内部工作原理和数据库设计有充分的了解。如果您只是刚开始,您可能不知道以后可能会遇到的某些问题,因此这里是不完整的列表。

性能

运行时性能足够好,我还没有看到冬眠是生产性能不佳的原因。问题在于启动性能以及它如何影响您的单元测试时间和开发性能。当休眠加载时,它会分析所有实体并进行大量预缓存-对于不太大的应用程序,可能需要5-10-15秒。因此,您的1秒钟单元测试现在将花费11秒。不好玩。

数据库独立性

只要您不需要对数据库进行一些微调,它就会非常酷。

内存会议

对于每个事务,Hibernate都会为它“接触”的每个数据库行在内存中存储一​​个对象。当您进行一些简单的数据输入时,这是一个很好的优化。但是,如果由于某种原因需要处理大量对象,除非您自己明确且仔细地清理内存中的会话,否则它可能会严重影响性能。

级联

级联使您可以简化对象图的使用。例如,如果您有一个根对象和一些子对象,并且保存了根对象,则可以将休眠配置为也保存子对象。当您的对象图变得复杂时,问题就开始了。除非您非常谨慎并且对内部发生的事情有充分的了解,否则很容易将其弄乱。而且当您这样做时,很难调试这些问题。

延迟加载

延迟加载意味着每次加载对象时,休眠将不会加载其所有相关对象,而是会提供占位符,当您尝试访问它们时将对其进行解析。优化效果好吗?是的,除非您需要了解此行为,否则您将得到隐秘的错误。以Google“ LazyInitializationException”为例。并注意性能。根据加载对象和对象图的顺序,您可能会遇到“ n + 1选择问题”。谷歌它的更多信息。

架构升级

Hibernate只需重构Java代码并重新启动,即可轻松更改架构。一开始就很棒。但是随后您发布了版本1。并且,除非您想失去客户,否则需要向他们提供架构升级脚本。这意味着不再需要简单的重构,因为所有模式更改都必须在SQL中完成。

视图和存储过程

Hibernate需要对其使用的数据具有独占写入权限。这意味着您不能真正使用视图,存储过程和触发器,因为那些视图,存储过程和触发器会导致休眠状态下的数据更改(不知道)。您可以让一些外部进程在单独的事务中将数据写入数据库。但是,如果这样做,缓存将包含无效数据。还有另一件事要注意。

单线程会话

休眠会话是单线程的。通过会话加载的任何对象只能从同一线程访问(包括读取)。这对于服务器端应用程序是可接受的,但是如果您正在基于GUI的应用程序,则可能会使不必要的事情变得复杂。

我想我的意思是没有免费的饭菜。

Hibernate是一个很好的工具,但它是一个复杂的工具,需要时间来正确理解它。如果您或您的团队成员不了解这些知识,则对于单个应用程序使用纯JDBC(或Spring JDBC)可能会更简单,更快。另一方面,如果您愿意花更多的时间来学习它(包括边做边学和调试),那么将来您将能够更好地了解这些取舍。


5
+1个好答案..我曾经认为Hibernate是有史以来最好的事情,但是随着我们的应用程序变得越来越复杂(更大的对象图),我遇到了一些调试是噩梦的场景,因为我不知道什么是Hibernate。在做。(幸运的是,它是开放源代码,所以我能够在源代码中进行挖掘以弄清楚。不是很有趣)无论如何,我同意。休眠功能很棒,但也需要权衡取舍。
delux247

1
自从它第一次在Google上流行以来,它仍然是最新的吗?
PowerFlower

@PowerFlower对于2018年,我认为这仍然是非常相似的情况,休眠的核心特征没有改变,并且可能永远不会改变。
user218867 '18

20

Hibernate可能很好,但是它和其他JPA ORM往往会在一定程度上决定您的数据库结构。例如,复合主键可以在Hibernate / JPA中完成,但是有点尴尬。还有其他例子。

如果您熟悉SQL,我强烈建议您看一下Ibatis。它可以完成Hibernate的90%以上的工作,但是实现起来要简单得多。

我想不出为什么要选择Ibatis的直接JDBC(甚至是Spring JDBC)的单一原因。休眠是一个更复杂的选择。

看看Spring and Ibatis教程


12

毫无疑问,Hibernate具有其复杂性。

但是,我真正喜欢Hibernate方法(还有其他一些方法)的是,您可以在Java中获得更好的概念模型。尽管我不认为OO是万能的灵丹妙药,而且我也不追求设计的理论纯度,但是我发现了很多次,OO确实简化了我的代码。如您特别要求的详细信息,以下是一些示例:

  • 例如,增加的复杂性不在模型和实体中,而在您用于操作所有实体的框架中。对于维护者来说,困难的部分不是几个框架类,而是您的模型,因此Hibernate允许您将困难的部分(模型)保持在最干净的状态。

  • 如果在您的所有实体中都使用了字段(例如ID或审核字段等),则可以使用该字段创建超类。因此:

    • 您编写的代码更少,但更重要的是...
    • 您的模型中的概念更少(唯一的概念在代码中是唯一的)
    • 免费,您可以编写更通用的代码,该代码随实体提供(未知,没有类型转换或强制转换),可让您访问ID。
  • Hibernate还具有许多功能来处理您可能需要的其他模型特征(现在或以后,仅根据需要添加它们)。将其视为设计的可扩展性

    • 您可以通过组合(具有相同成员的几个实体,其中包含几个实体中需要的几个相关字段)来替换继承(子类)。
    • 您的几个实体之间可能存在继承。通常,您有两个具有几乎相同结构的表(但是您不想将所有数据存储在一个表中,因为您会将参照完整性放到另一个父表中)。
  • 随着实体之间的重用(但只有适当的继承composition),通常会有一些其他优点。例子 :

    • 通常有一些方法可以读取相似但不同的实体数据。假设我读取了三个实体的“标题”字段,但是对于某些实体,如果结果为null,则将结果替换为不同的默认值。具有签名“ getActualTitle”(在超类或接口中)并在这三个实现中实现默认值处理很容易。这意味着我实体中的代码仅处理“实际标题”的概念(我明确说明了此功能性概念),并且方法继承负责执行正确的代码(不再进行切换,或者如果没有代码重复) 。
    • ...
  • 随着时间的流逝,需求不断变化。在某种程度上您的数据库结构有问题。仅使用JDBC,对数据库的任何更改都必须影响代码(即,双倍成本)。使用Hibernate,仅更改映射而不更改代码可以吸收许多更改。反之亦然:Hibernate允许您更改代码(例如,在版本之间),而无需更改数据库(更改映射,尽管并不总是足够的)。总而言之,Hibernate让您独立地开发数据库和代码

由于所有这些原因,我会选择Hibernate :-)


5

我认为这两者都是不错的选择,但就我个人而言,我将使用休眠模式。对于这种规模的项目,我认为冬眠并不过分。

Hibernate真正让我着迷的是处理实体/表之间的关系。如果您要同时修改父母和子女(孙子女,兄弟姐妹等),那么手工执行JDBC可能会花费大量代码。Hibernate可以使此工作变得轻而易举(通常只需保存一次父实体就足够了)。

但是,在处理Hibernate时肯定会有一些复杂性,例如了解会话刷新的工作方式以及处理延迟加载。


3

直接JDBC最多适合最简单的情况。

如果您想保留在Java和OOD中,则选择Hibernate或Hibernate / JPA或任何其他JPA提供者/ JPA是您的选择。

如果您对SQL更熟悉,那么拥有适用于JDBC模板的Spring和其他面向SQL的框架将不会受到伤害。

相比之下,除了事务控制之外,使用JPA时使用Spring并没有太多帮助。


3

Hibernate最适合中间件应用程序。假设我们在数据库之上构建了一个中间件,那么大约有20个应用程序可以访问中间件,在这种情况下,我们可以拥有一个满足所有20个应用程序需求的休眠模式。


当涉及到测试或调试时,您是否会感到头痛?
重生

1
  1. 在JDBC中,如果我们打开数据库连接,则需要在try中编写代码,并且如果发生任何异常,catch块将接受它,最后用于关闭连接。

  2. 在jdbc中,所有异常都是经过检查的异常,因此我们必须在try,catch和throws中编写代码,但是在休眠状态下,我们只有未检查的异常

  3. 在这里,作为程序员,我们必须关闭连接,否则我们将有机会获得连接消息……!

  4. 实际上,如果我们没有在finally块中关闭连接,则jdbc不负责关闭该连接。

  5. 在JDBC中,我们需要在各个位置编写Sql命令,在程序创建后,如果表结构被修改,则JDBC程序将无法正常工作,同样,我们需要修改,编译和重新部署,这很繁琐。

  6. 如果发生异常,JDBC用来生成与数据库相关的错误代码,但是Java程序员对此错误代码一无所知。

  7. 当我们插入任何记录时,如果我们在数据库中没有任何特定的表,则JDBC将引发诸如“视图不存在”之类的错误,并引发异常,但在休眠的情况下,如果未在数据库中找到任何表数据库将为我们创建表

  8. JDBC支持LAZY加载,而Hibernate支持Eager加载

  9. Hibernate支持继承,关联,集合

  10. 在hibernate中,如果我们保存派生的类对象,则其基类对象也将存储到数据库中,这意味着hibernate支持继承

  11. Hibernate支持诸如一对多,一对一,多对多对多,多对一的关系

  12. 通过这种方式,Hibernate支持缓存机制,将减少应用程序与数据库之间的往返次数,通过使用这种缓存技术,应用程序性能将自动提高。

  13. 在休眠状态下进行分页非常简单。

  14. 当我们将记录存储到数据库中时,Hibernate具有自动生成主键的功能


Java 1.7发行版及其功能try-with-resources。参数1,3和4不再是问题
重生

0

...内存中的会话... LazyInitializationException ...

您可以看一下不使用会话对象的Ebean ORM ...以及仅在惰性加载起作用的地方。当然是一种选择,不是矫not过正,而且更容易理解。


0

如果数十亿用户使用了应用程序或Web,则在jdbc查询中将执行数十亿次时间,但在休眠查询中,对于任何数量的用户而言,与jdbc相比,最重要和最简单的休眠优势将仅执行一次。

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.