几个月来,Versant,一家老牌的OODBMS供应商,其市值正在萎缩,一直在在线网络研讨会和销售演示中关于Hibernate提出各种虚假声明。我甚至写了一篇博客来反驳他们的声明,但后来又推迟发表,因为我认为他们不配得到关注。现在,他们已经转而大量发送一份关于Hibernate的虚假声明的文件,我们决定我们需要对此作出回应。
(如果你没有被Versant的垃圾邮件打扰,或者知道要对此持极端怀疑态度,你可能不需要继续阅读。)
我将逐点回答文档中的声明。我不会费心争论Hibernate更好还是Versant更好,或者任何其他问题。相反,像往常一样,我鼓励潜在用户试用这两种产品,看看哪一个最适合他们。
一个警告:其中一些声明对于Hibernate 2.1是真实的,但不是对于Hibernate 3.0(更新:大约40个虚假声明中的10个)。但我所回应的文档是在Hibernate 3.0 rc1发布后的两周发送的,这是Hibernate的第一个生产就绪版本。我认为,竞争材料应该引用最新的当前生产就绪版本,而不是以前的版本,尤其是考虑到所有新功能在过去六个月中都在Hibernate的beta版本中可用,并且已经在Hibernate 3.0功能列表中完全记录,这个列表也已经几个月可用。如果Versant好奇,很容易就能确定这些新功能的存在。现在进行产品评估的项目对Hibernate 3.0的功能感兴趣,而不是Hibernate 2.1。
Hibernate has drawn a lot of attention in the Java community as a solution for transparent persistence with Java based applications. The big deal seems to be that it is free...
不,真正重要的是它行得通。在实践中。
Hibernate 负责在 Java 中普及 ORM 技术,并帮助创建了一个市场,Versant 现在希望利用这个市场,因为它的核心对象数据库技术继续在市场上失败。然而,一个多年来试图说服世界关系型技术是过时的公司,现在不太可能将自己重塑为一个可信的对象/关系映射技术供应商。尤其是当至少有三个供应商在这个领域已经远远领先,他们的产品具有更高的成熟度和更大的用户基础——他们中没有一个是关系数据库的“敌人”。
This paper points out the pitfalls of the Hibernate solution while showing how JDO implementations, specifically Versant Open Access JDO, addresses those pitfalls. Where appropriate, it discusses the strong points of Hibernate in order to give a fair analysis for the informed reader.
哦,别逗了。Hibernate 有许多 Versant Open Access JDO 所不具备的功能,这些功能在接下来的文档中都没有提到。
More importantly, the tools available to the developer using Versant Open Access - JDO and/or most other JDO vendors, are several orders of magnitude better than what's available with Hibernate
他们是如何衡量“好几个数量级”更好的?用卷尺吗?他们真的研究了 Hibernate 团队与 Versant 团队的效率,发现 Versant 团队在创建领域模型方面快了一千倍或更多吗?或者作者只是在胡编乱造?
我实际上会承认我们的工具集可以改进。这就是为什么我们现在有一个由 Max Andersen 领导的全职开发团队,正在构建一个雄心勃勃的开源 Eclipse 插件套件,用于 Hibernate 和 EJB 3.0。一些插件的预览版本在此处可用
http://www.hibernate.org/Projects/HibernateTools
这是 JBoss 的一个重大战略举措,所以预计这些功能会非常快速地变得非常出色。
In fact, if you go to the Middlegen website and look at their ( online Middlegen demonstration ) , you will see that they are showing CMP, JDO & Struts not Hibernate. So, you can imagine the amount of support you get from the technical leads of those open source initiatives for the Hibernate integration.
Hibernate 团队成员 David Channon 负责维护和支持 Hibernate middlegen 插件。我相信 Hibernate 用户会证实 David 的有帮助性支持的价值。他的当前 Hibernate 论坛帖子数约为 1300 篇——其中大部分是关于 Middlegen 的免费支持。(David 的帖子数是 Versant JDO 论坛总帖子的四分之一。)
(实际上,基于 Middlegen 的逆向工程已被终止,现在有一个全新的基于 Eclipse 的逆向工程插件,可在 Hibernate Tools 预览版中找到。)
When it comes to things like monitoring and performance tuning, you are left completely to your own devices because Hibernate offers nothing to help.
这不是真的,Hibernate 3.0 提供了复杂的 JMX 监控功能,以及大量的性能调整选项。
In Hibernate, there are no visual tools for editing meta data or relational mapping that come out of the box.
Hibernate Tools 提供了一个 Hibernate 映射文件编辑器,作为一个 Eclipse 插件,具有自动完成类、属性、表和列名。这是创建映射文档最快、最有效的方法,比我们尝试过的笨拙的视觉工具效率高得多。此外,Hibernate 现在支持基于 EJB 3.0 注释的映射,这更加容易使用。
The lifecycle states in Hibernate are not only insufficient, but also incomplete in their implementation.
真的吗?你有任何论据来支持这一点吗?
哦,这里有一个例子...
For example, the update callback in Hibernate which is used to notify when an objects state has changed and is going to be updated in the database is only called when the object is a transient object and being sent back for update. It is not called on any change of a persistent object that will cause an update to the database.
这表明文档的作者实际上并不了解 Hibernate。Lifecycle.onUpdate() 回调用于在调用 update() 时通知应用程序一个分离对象正在变为受管理。还有一个完全不同的回调 - Interceptor.onFlushDirty() - 它用于通知应用程序即将发生 SQL UPDATE。我不确定作者为什么找不到这个回调,这个回调在社区中被广泛记录和理解。
为了澄清 Hibernate 定义的生存周期模型:该模型与 TopLink 使用的生命周期相同,并已被 JSR-220(EJB 3.0)标准化。
Also, the create callback is not called when identity is managed by the database's native key generation which is the most common form of key generation (for example: Identity tables in DB2 and Sequences in Oracle).
这根本不是真的。作者显然从未尝试过。
The following summarizes the Hibernate coding impositions. 1. You need to add an identity attribute and methods to your classes ( getId( ) , setId( ) ). Note that this is not strictly mandatory, but you must implement these if using the Hibernate disconnected model capabilities.
能够访问持久实例的主键总是很有用。这不是限制,这是一个功能。
The disconnected model in Hibernate is a limited form of the attach/detach capabilities found in JDO.
JDO 2.0 中找到的功能(在 JDO 1.0 中不存在)受到了 Hibernate 的启发,以及我对 JDO 的批评。将 Hibernate 的功能描述为一种 有限形式
是不诚实且误导的。分离/重新附加模型略有不同,但我们认为我们的功能更强大且更容易使用。
2. Your classes must implement Java Beans style accessors for all persistent attributes. There are no such restrictions in JDO.
这根本不是真的。Hibernate 不需要 getters 和 setters,这在 Hibernate 网站上的许多地方都有明确描述。
3. Because of Hibernates runtime proxy generation through the use of CGLIB, calls to getClass can return the wrong type, so if you need to access the class of an object you have to use Hibernate static methods. Hibernate.getClass( foo ) instead of the traditional foo.getClass( )
这有什么大不了的?这算什么 强制
么?
如果你 /真的/ 想要能够使用 getClass(),你可以在 Hibernate 3.0 中使用实例变量拦截而不是代理来实现延迟加载。当然,我们不期望任何 Hibernate 用户走这条路,因为代理对大多数人来说更方便。
4. Application Identity classes with composite id's must implement Serializable. This is only required if you want the class itself to manage identity rather than creating an identity class. This is also a restriction in Versant Open Access JDO. The common practice is to use an application identity class and this bullet is included mainly for completeness.
哇,这是可能的吗?Versant Open Access JDO 有限制吗?当然没有!
5. Polymorphic classes should implement hashcode and equals methods. This is only required if the objects are going to be accessed by multiple sessions and the shared cache is enabled. If you do not plan for this up front and then decide to scale later on and add application servers and clustering, something that should be an administrative task, suddenly your business logic might not be working properly and you won't even know it's a problem until you have many logical errors in your data.
这全部都是错误的或者难以理解。你只需要在持久化类上实现 equals() 和 hashCode() 的情况是,如果你打算将实例放入 HashSet 中,这是 Java Set 合约的要求,而不是 Hibernate 的要求。
6. Collections must be referenced as Interface types only. You cannot refer to a concrete implementation class of the interface. Versant Open Access JDO does not have this restriction.
这种 限制
是一种良好的编码实践。没有理由用 ArrayList 而不是 List 来编码;良好的面向对象实践要求我们面向接口进行编码。
如果你出于某种奇怪的原因需要针对具体的集合实现进行编码,Hibernate3 提供了一个扩展点,这样你可以做到这一点。没有 Hibernate 用户曾经要求支持具体集合类,所以我们没有费心将其作为标准功能实现。
你可能会认为 Versant 会真正尝试发现实际 Hibernate 用户在实践中的真实问题,而不是提出像这样的误导性信息。
7. Hibernate does not guarantee the order of loading attributes in your class, so your setter methods cannot reference other attributes within your class. This is because the setter methods are used at runtime when loading an object from the database and it is possible that you are accessing a field that is not loaded yet.
这不对,Hibernate 保证在映射文档中列出的顺序中填充属性(通过 setters 或直接实例变量访问)。
It is worth pointing out that Hibernate uses checked exceptions.
Hibernate 3.0 有一个未检查的异常模型。
However, it is not clear why there is any exception handling at all in Hibernate. The reason is as stated in the Hibernate documentation, Hibernate cannot guarantee the state of the Hibernate Session if any kind of exception occurs.
正确,这与 TopLink 相同,与一些 JDO 实现不同。我目前正在与 Mike Keith(Oracle)和 Patrick Linskey(Solarmetric)讨论,了解在 EJB 3.0 规范中允许可恢复异常是否有任何好的案例,如果我们发现一些(Patrick 似乎认为有一些),我们当然会在 Hibernate 中实现这一点。
我对这一点持开放态度;我意识到这里有一些复杂和微妙的问题。然而,观察到一个最成熟、最常用的非委员会设计的 ORM 解决方案(Hibernate 和 TopLink)从未发现支持可恢复异常的强烈需求是有用的。偶尔,用户要求某些异常是可恢复的,但我总是能够提供满意的替代方案。
If you want to move a deterministic set of objects to another tier, you have to resolve these yourself. Each object must have been loaded from the database before you can detach (close the Hibernate session), so you must touch each object to cause it to initialize. For collections, you would have to use a static method Hibernate.initialize().
这不对,所有的 Hibernate 查询工具都提供了一种方法,可以在分离对象图之前轻松指定哪些关联将被检索。你绝对不需要在对象图中调用 initialize() 来遍历。
Once you've sent the objects to the disconnected tier, you need to be very careful not to traverse relationships outside of the disconnected graph or you will get a fatal exception.
相反,异常不是致命的,因此这种行为与 Versant 的行为完全相同。
Once you've changed the objects, then when you send them back you must either individually call update( ) on each object or configure cascading meta data. Once again, using cascading meta data does not work through collections.
这不对。你可以轻松地在集合上启用级联。
So, in most cases you will be forced to implement this yourself. In addition, Hibernate does not know which fields have changed or if the object has really been updated. By default, when you call update( ) it will perform an UPDATE operation of the object even if it has not changed. This means that configuring meta data to automatically call the update will ALWAYS do an update operation even if the object has not changed. If you have triggers defined in the database this will lead to false triggers.
有一个名为 select-before-update 的选项,作者显然没有意识到,尽管它有详细的文档。
Hibernate provides a way to work around this inadequacy ONLY if you are using optimistic transactions with the version/timestamp option. You can call a method to check if the object has changed prior to actually doing the update. However, since Hibernate does not track dirty fields, it must do a field by field comparison of all fields to determine what needs to be updated. This has obvious performance implications.
这一切都不对,我完全不知道作者在说什么。Hibernate 没有这样的功能。相反,它有上面提到的简单开关。
To say that the Hibernate detach behavior is flawed is an understatement.
说这篇文档的作者不理解 Hibernate 的分离行为是一种巨大的低估。
注意,Hibernate 3.0 完全支持 JSR-220(EJB 3.0)定义的 persist()/merge() 生命周期。
Hibernate, out of the box, uses EHCache for their level 2 cache which is not clusterable. This is another open source product that has difficulty staying in sync with product updates.
这绝对不是真的。EHCache(代表Easy Hibernate Cache)是在我的建议下由Thoughtworks的Greg Luck创建的。Greg在每次发布EHCache之前都会对Hibernate的最新版本进行大量测试,并且我们保持着定期的电子邮件联系。从来都没有过任何关于保持同步
的问题。我甚至不确定保持同步
是什么意思;也许作者并不了解软件开发中关于已发布API
的概念,这有助于不同的软件组件协同工作。
They used to support JCS cache, but have deprecated it's use and who knows how long EHCache will last.
EHCache是Apache JCS的一个分支,并创建出来修复JCS中的几个错误。JCS两年前就被弃用了!这完全是虚假的恐惧宣传。完全没有计划停止对EHCache的支持。即使有,这里到底有什么问题?可插拔缓存架构的整个要点是,应用程序对缓存实现没有依赖性,部署时间可以完全交换。
Hibernate does support two different cluster caches ( SwarmCache and JBoss TreeCache ). However, none of their clustered cache implementations support query caching, so by introducing these clustered caching solutions you introduce a potential performance degradation.
这不是真的,根据Hibernate文档,Hibernate查询缓存与JBoss Cache兼容。
Hibernate does query caching by using a system level caching option must be enabled, and then in addition, individual queries must be configured to cache their results. Also, no referenced objects are cached, only their OIDs. So far, this is pretty consistent with Versant Open Access JDO. However, since only oids are cached, query caching is really only useful if using the second level shared cache. In fact this is stated explicitly in the Hibernate documentation. However, the only shared caches that support clustering do not support query caching. Versant Open Access JDO does not have this restriction.
除了JBoss Cache支持查询缓存之外。哦,糟糕,这打破了整个说法。
CGLIB Side effects: Hibernate cannot not properly implement polymorphism due to it's runtime byte code generation.
这完全不对,所有Hibernate查询和关联映射完全支持多态性。
What is meant here is that you cannot query on a super class and then cast to the subclass type or a similar type of operation. Subclass casting is not allowed.
这也不对,在业务逻辑确实需要执行类型转换的极少数情况下,可以使用get()方法进行类型转换。
顺便说一句,多态的整个要点是你不需要进行类型转换,所以如果作者认为支持多态性意味着支持类型转换,那么他对多态性的理解是错误的。
Also, you cannot use any Final class or any class that has Final methods. Of course, if these things are important to you then you can get them back by not using the runtime proxies and reverting to the old reflection model.
什么是一个大写的Final
?作者是指Java的final
关键字吗?如果是这样,他/她部分正确:final类不能被代理(除非它实现了一个接口),在这种情况下,如果你真的想的话,可以使用实例变量拦截进行懒加载(就像Versant一样)。在实践中,没有Hibernate用户关心这一点。
(我们实际上实现了实例变量拦截,不是响应用户的请求,而是为了消除商业供应商如Versant等造成的这种恐惧宣传。)
Finally, something that I have not fully comprehended the implications of: If any resources are initialized in a constructor or initializer method, then those resources will also be held by the proxy. I think that there may be no way to release these resources when the actual object is flushed or committed/evicted from the cache.
这个人在这里说些什么?显然,作者此时已经陷入了纯粹的无稽之谈。
Does not support semantics of the collection like iteration ordering on LinkedLists, but it does not go into detail and list which of these semantics are unsupported in the documentation.
Hibernate当然支持列表的迭代顺序
,显然作者误解了Hibernate文档中的一个注释。
Hibernate3提供了UserCollectionType扩展点,可以用于支持任何你喜欢的集合和集合语义。
One to many associations that do not use a JOIN table and have a NOT_NULL constraint on the key will fail on commit if there is no bi-directional association defined in the model. So, you must have a bi-directional association if the key has a NOT_NULL constraint.
在Hibernate 3.0中这不是真的。
Hibernate does not support one to many collections where the many is an indexed collection. Also a restriction in Versant Open Access JDO.
在Hibernate 3.0中这不是真的。
哦,我们刚刚发现Hibernate的一个功能,而Versant没有?这怎么可能呢?
Hibernate supports Flat, Vertical and Horizontal inheritance mapping. Flat mapping has a restriction that none of the columns in a subclass can have a NOT_NULL constraint.
是的,这是每个ORM实现的真实情况。
We do not have any restrictions on constraints for Flat mapping.
相反,子类属性在单表或扁平
映射策略中不可能是非空的。显然,作者甚至不知道自己的产品。使用数据库CHECK约束强制执行正确的nullability语义是可能的,Hibernate在其DDL导出功能中支持这一点。
Horizontal mapping does not support polymorphic associations which would necessitate multiple queries across concrete tables.
在Hibernate 3.0中这不是真的。Hibernate3可以使用SQL UNION,这允许做很多其他事情,包括多态关联。
Also, Hibernate uses a top down approach to inheritance mapping. This means that subclasses inherit their supers mapping strategy. The implications are that you cannot combine mapping strategies for a set of subclasses from a common superclass. For example, a class that drives two subclasses cannot map one of the subclasses vertically and the other flat.
在Hibernate 3.0中这不是真的。扁平
和垂直
可以自由选择用于特定的子类。
Today, Versant Open Access JDO supports Flat and Vertical mapping only.
啊,所以,Hibernate的继承支持更灵活。想象一下。
Versant Open Access JDO supports polymorphic associations in all supported mapping strategies.
就像Hibernate3一样,我们观察到Hibernate支持一种额外的继承映射策略,而Versant还没有。
Database Constraints: Hibernate does not know how to order insert statements to deal with NOT_NULL constraints on foreign key columns.
这不对。当启用级联持久化或级联保存时,Hibernate正确地排序INSERT。
We did not specifically address performance in the above, except to reference the Hibernate move from a purely reflective to a runtime byte code enhancement model. The issues of taking this later approach due to performance problems in the former is something well documented in the Hibernate manuals. If you crawl the web looking for more information on performance, you will find that there are several benchmarks done where JDO vendors out perform Hibernate.
胡言乱语。我见过Hibernate在基准测试中获胜的案例。我也见过TopLink获胜的案例。还有CMP获胜的案例。根据我们的经验,通常获胜的解决方案是那些基准测试者最熟悉的那一个。(我自己与一个领先的JDO解决方案进行的基准测试表明,Hibernate在大多数指标上都获胜,但我并不声称这是一个普遍的结果。)
除了这个模糊的断言之外,作者没有勇气真正声称Versant Open Access JDO实际上比Hibernate更快,这大概意味着Versant并不真正相信这一点。这是我们达成共识的一点。
The above has addressed many of the misconceptions found in the Hibernate community regarding Hibernates superiority over JDO. I think that from a technical perspective, there is a strong case that those misconceptions are completely unfounded.
实际上,上面的内容是一长串错误陈述和半真半假的说法,由一个对Hibernate知之甚少的人编写的,他们只是对用户手册进行了表面的阅读。
此外,我必须问,这些问题是否与真实企业应用程序中管理真实数据的问题有关?ORM中的许多有趣问题甚至没有在这个文档中解决。Versant如何处理复杂的历史数据?如何处理时间、地区或授权数据?是否允许完全覆盖任何生成的SQL?能否从查询语言中调用数据库特定功能?如何处理搜索屏幕上的动态查询?能否生成XML或映射动态
实体定义?如何扩展?如何高效地获取关联?有多少用户真正在愤怒中使用Versant Open Access JDO?Hibernate可以吹嘘有数万名满意的用户;为什么他们要开始为一个现在已经由免费软件非常有效地解决的问题支付封闭源代码解决方案的费用呢?