正如旧金山雾气一样可预测,每隔几个月,我们都会看到某些公司或开源团体又宣布通过消除关系型数据库来解决了对象关系映射(ORM)的“复杂性”。承诺大大提高开发者生产力,以及惊人的性能提升,通常比现有技术高两个或三个数量级。最令人惊讶的是,这么多不同的团体似乎完全独立地实现了这样的突破,然而,这些技术的企业采用率仍然大约为零。这里发生了什么事?是否无所不能的甲骨文公司秘密地勒索了美国所有的CIO?好吧,让我们通过更仔细地观察这些系统的所谓好处来更好地理解这个悖论。
首先,一个简短的术语说明:这些系统过去被称为“对象数据库”。由于1980年代“对象数据库”的彻底失败,在今天的营销文献中,这些系统通常不被称为“对象数据库”,但我们仍然这样称呼它们,因为这就是它们。
好处#1:消除对象/关系映射的复杂性!
这里所指的“复杂性”是指提供有关类和属性如何与数据库表和列相关联的信息的成本。ORM解决方案支持通过某种领域特定语言(通常是基于XML的)或通过类和属性的注释来指定此类信息。但通常只有当我们需要映射到现有的遗留数据库或由组织中的某个外部团体拥有和管理的某些模式时,我们才需要此类信息。消除关系型数据库当然解决了现有模式的问题,但我们不必消除数据库来实现这一点:地球上的几乎每个ORM解决方案都具有从对象模型自动正向生成模式的能力,无需指定映射信息。事实上,只有在需要映射信息的确切情况下(遗留数据库等)才能通过ORM以外的任何技术来处理!
为了明确,使用ORM技术不会引入新的映射或双模式问题,除非你已经存在这样的问题,这是由于访问旧数据的要求。如果你想“把一些对象扔到数据库里”,你永远不需要写一行映射注解。
所以,从这个角度来看,ORM对于所有用例来说至少和对象数据库一样好,而且处理了对象数据库方法不处理的其他用例(实际上,是常见的用例)。
我不是说映射到旧数据模型不会复杂、痛苦且耗时。它确实可以,而且通常就是这样。旧数据库通常和大多数Java代码一样糟糕。但如果你必须与那些旧数据打交道,你就必须与之打交道。没有任何新技术会改变这个基本要求。ORM技术确实使它更容易相处。
核心来说,我们需要映射技术的原因是数据和数据模型比应用程序存在的时间更长,甚至比编程语言更长。数据在企业中的许多应用程序之间共享,而且它们并不都是用Java编写的!映射技术让使用数据模型的应用程序可以为事物拥有自己的美好名称,而无需强迫每个人就什么是“美好”达成一致。
假设IT行业在集体自我陶醉的短暂攻击中,真的决定撕掉所有那些生锈的庞大关系数据库,用闪亮的新的对象数据库来代替。再过十年,我们就会听到关于对象/对象映射的“阻抗不匹配”问题的所有关于。
优点#2:支持原生Java类型系统
关于对象数据库技术(以及20世纪80年代短暂流行的对象/关系数据库技术)的酷之处之一是,数据库可以拥有比传统SQL数据库中可用的简单原始类型更丰富的类型系统。能够有一个类型为Duration(来自Joda Time API)的属性,而不是不得不将其映射回关系数据库类型,这不是很好吗?
这对我们来说确实很好,但对那个后来者来说就不那么好了!他可能是一位闪闪发光(而且有些吓人)的Ruby狂热者。或者他可能是一位VB开发者(当然,年长者也很重要)。或者,也许5000年后:Java和Ruby都已经消失(当然,VB仍然强大),一群来自土卫二的考古学家正在尝试从你的客户数据库留下的残骸中拼凑出关于我们遗忘的文明的一些东西,使用最近发布的Perl 6.0。如果数据库中只有字符串和数字,对他们来说不是更容易吗?
优点#3:纯Java实现
这些新的对象数据库系统真正有益的一点是,它们往往是用Java实现的。我多么希望有一个真正成熟的纯Java RDBMS!不幸的是,如果我们现在开始构建它,等到我们完成的时候,Java的日子就快到头了。而且当你是一位CIO,在投资数据管理系统时,你是在为长远投资。你更关心整个数据管理平台的成熟度(这不仅仅意味着OLTP),而不是一个臭屁的Java开发者团队是否方便。CIO们明白这些事情。这就是他们比我们赚更多的原因。(混蛋。)
如果全世界都使用Java,那当然很好,但他们没有。而且Java不会永远存在。真的不会。嘿嘿,只要它不是Ruby取代它(我可以这样放心地说,因为我被一支精英团队五百名全副武装的女IDF特种部队保护着,她们装备着《异形II》中的大口径机枪)。
遗憾的是,为了让MyReallyFastThingyButDontCallItAnObjectDatabase 1.0 beta 3达到现有关系型数据库管理系统(RDBMS)的成熟度,所需时间与在Java中构建RDBMS所需时间相当。当大家都开始转向更好的东西(即除了Ruby之外的其他东西)时,它将准备好用于真正的企业级生产使用。
优势 #4:比Hibernate快2537754.54%!!!
看吧,一个完全客观的基准测试来证明这一点!他们甚至为编写的基准测试建立了一个网站,只是为了展示其客观性!它是开源的,他们还邀请社区贡献!你能有多客观呢?
任何了解软件行业的人都知道,基准测试是第三种谎言,仅次于“谎言”和“该死的谎言”。每当有人试图用基准测试来愚弄你时,他们就是在对你撒谎,而且他们知道自己在撒谎。幸运的是,在软件行业的历史上,很少有组织根据基准测试做出采购决策。
想象一下,如果MyReallyFastThingyButDontCallItAnObjectDatabase 1.0 beta 3真的比Hibernate快2537754.54%。数据访问是广泛类别的企业应用程序性能的限制因素,因此这可能会从IT预算中节省数亿美元!然而,没有人对此感兴趣。拉里一定有一些非常肮脏的照片,那些病态的CIO们。
或许这里的内容并没有表面看起来那么多。为什么对象数据库会更快呢?
它们在进程中运行
这些解决方案通常是在与应用程序相同的进程中运行进行基准测试。在许多情况下,这是它们唯一能运行的方式。但在真实的企业环境中,你只有在某些情况下才有可能将数据库与应用程序服务器放在同一台机器上运行。当你这样做时,运行在进程中当然会很方便,但这并不是关系型技术的概念问题,问题在于现有的、成熟的RDBMS系统恰好不是用Java编写的(参见优势 #3)。
数据访问成本的最大部分是进程间或网络调用的成本。实际上,与ORM一起工作的许多复杂性都围绕通过调整关联检索策略来最小化进程间调用。如果我们用Hibernate对HSQLDB进行基准测试,我们会得到与MyReallyFastThingyButDontCallItAnObjectDatabase在其营销手册中声称的性能提升相同,同时消除了对关联检索的精细调优的需要。遗憾的是,我们也得到了与MyReallyFastThingyButDontCallItAnObjectDatabase相同的可靠性和可伸缩性水平。
它们不可扩展
如果你有一个在并发线程之间共享大量状态的架构,那么在简单的基准测试中实现高性能是非常容易的。当然,一旦部署到集群或多CPU机器上,这就会崩溃。基于成熟的关系型解决方案(尤其是Hibernate)针对集群和高度并发的场景进行了优化,因此它们最小化了共享状态。这在小型规模的情况下会损害性能,但通常人们更关心的是在大规模时的性能。
它们在基准测试中关闭了ORM的缓存
呃!
这些基准测试通常是在禁用ORM解决方案中的二级缓存的情况下进行的。这真是太荒谬了。如果你打开二级缓存,一个好的ORM解决方案可以取得与对象数据库非常相似的性能水平,因为缓存最小化了导致所有问题的进程间调用。当我们处于单个进程中,没有外部进程更新数据库时(这是MyReallyFastThingyButDontCallItAnObjectDatabase唯一支持的架构),二级缓存非常高效。
这里有个众所周知的人物,他声称通过一个简单而独特的想法解决了关系技术的性能问题:把所有数据都保存在内存中!他说,内存如此便宜,以至于不再需要磁盘(我是在转述)。他的基准测试显示,与Oracle等相比,性能提升了多个数量级。当然,他忘记的是,Oracle有自己的缓存!如果数据适合,Oracle已经将数据保存在内存中。他测量的性能差异并不是由于磁盘访问的成本,而是由于进程间通信的成本。这位先生还卖假药,如果你感兴趣的话。
功能越多的东西越慢
众所周知,随着软件产品的增长,它们的运行速度会变慢。Hibernate3比Hibernate 1.0慢。Oracle比HSQLDB慢。现在的MS Word比以前的慢。你之所以没注意到,是因为你的电脑比Word慢得更快。在Oracle上运行的Hibernate比MyReallyFastThingyButDontCallItAnObjectDatabase 1.0 beta 3慢。但一旦MyReallyFastThingyButDontCallItAnObjectDatabase团队修复了他们beta版本中的所有大量bug,一旦他们花了另外四年时间添加功能、解决可扩展性问题,并添加集群部署的可能性,差距就会消失。
那么,这是否意味着我们应该时不时地抛弃所有现有的软件,用beta版本替换它们?当然不是,每一个小bug修复和性能的微小提升都是值得的。这是否意味着运行速度慢的软件总是比运行速度快软件的bug少?甚至不是这样。这只意味着你应该尝试比较成熟度水平和功能相似的产品性能。
获取层次化数据
人们经常声称,对象数据库有助于在从远程服务器获取数据时消除n+1请求问题。然而,没有先验理由说明对象数据库应该比ORM解决方案快。现代ORM解决方案提供了非常高效的关联获取策略和调整获取策略的选项。然而,我承认,有一种特殊情况,当前的数据库技术不如:在层次关系中对任意深度数据图的获取。没有任何理由说明标准SQL不能提供优化这种情况的功能,事实上,某些供应商已经有了专有的扩展。而且,没有很好的技术理由说明ORM解决方案不能利用这些扩展。然而,据我所知,目前还没有任何产品这样做。
结论
如果你认为关系技术是用来持久化应用程序状态的,那你已经错过了重点。关系模型的价值在于它的民主性。任何编程语言都可以理解原始值元组的集合。关系数据库是集成技术,而不仅仅是持久化技术。集成很重要。这就是我们为什么离不开它们。
ORM使得大多数情况下可以轻松地与对象和数据库一起工作。与五六年相比,ORM已经解决了在线应用中的大多数数据访问问题。它不再像以前那样痛苦。剩余的问题往往来自三个来源。
首先,大多数编程环境中缺乏对话模型,这阻碍了人们充分利用ORM技术,并为新用户带来了无尽的痛苦。(LazyInitializationException,有人听说过吗?)这就是为什么Seam和Web Beans对于使用ORM的人来说如此重要的原因。
其次,一些真正疯狂的遗留模式仍然可能引发问题。ORM实现一直在悄然添加新的功能来处理遗留数据,因此随着时间的推移,这个问题会逐渐改善。但真正的解决方案在于组织文化的转变。数据管理专业人员需要开始将他们的数据模型和数据库模式视为对组织具有持续价值的持续项目,这些项目需要持续维护和演进。他们需要停止将遗留模式视为上帝赐予的不可更改的圣书。数据库重构是可能的,也是实用的(向Scott Ambler致敬)。
最后,有些人仍然没有使用ORM,或者使用的是不成熟的ORM解决方案。这在Ruby社区中尤为突出,因为Ruby社区缺乏合适的持久化解决方案,部分原因在于Ruby开发者倾向于持续地进行传教/防御模式(与Java传统的激烈自我批评相比),以及Ruby允许构建的应用类型通常不具备Java世界中有趣项目所具有的复杂遗留数据模型、复杂业务逻辑和大规模部署的特点。但我的预期是,在某个阶段,Ruby世界中的某个人将进行足够的自我审视,认识到他们需要将Hibernate迁移到Ruby。
或者他们可能只是期待为Ruby提供MyReallyFastThingyButDontCallItAnObjectDatabase。我听说他们很快就会推出测试版。
/P.S. 这是我很久以前写的一篇文章,但因为我觉得它过于激烈,所以从未发布。随着Rails热潮的消退,现在大多数人都在回归实际工作,这些Ruby笑话已经有些过时了。