从我的亲身经历来说说我对ORM的一些看法
近来园子里对ORM的讨论又有升级的趋势,我也来凑个热闹。自知自己水平有限,说的不对的地方还请各位大虾指教。
对于ORM,我也是从最初的ORM工具开始接触到这块,想当初刚接触的时候用到的是DevExpress的商业化ORM组件XPO。这个项目当中让我觉得很爽的一点就是不用想怎么去拼那种复杂的SQL语句,对于复杂的查询,你要做的就是搞明白他们之间的代数逻辑关系。另外对于这个商业化的组件他还提供了对数据绑定的一个支持,并且根据反射机制以及ConnectionString的配置自动为你建立数据库和表,极大地提高了开发的效率。就这样,我便坚定的站在了支持ORM的一边。
对ORM接触了一段时间之后很自然就会知道在Java界大名鼎鼎的Hibernate,所以很自然的也就了解了.NET下有从他那里进行移植的一个兄弟:NHibernate。鉴于之前使用ORM的经验,我便在接手的一个研究性的项目中采用了NHibernate。但由于经验所限,实际上我们是使用由R到O的一个设计方法在使用ORM,结果正如大多数反对ORM的人一样,程序运行异常缓慢,对象之间的关系也异常复杂,很多业务层有效性的约束由于NHibernate的机制和数据库原理的冲突而不得不作出折衷方案,并且经常会引发各种异常。后来干脆直接就不采用ORM了,使用MS的EntLib来写DAL。
其实要使用ORM,首先我们要来看看为什么会有ORM?我们现在都强调使用面向对象的方式来进行编程,那么在程序进行逻辑处理的时候,对象是保存在内存中的。但是由于操作系统所支持的内存容量有限,所以我们需要把那些已经完成逻辑运算的对象保存到另外一个地方,等我们再次使用的时候再去取。这里所谓的另外一个地方其实就是我们的关系数据库。但是对象是一个多维结构,而数据库只是一系列二维表的集合,所以这里就有一个问题:怎么在这两者之间建立映射,并且不会造成信息的丢失呢?ORM的出现其实就是为我们解决这个问题。
说到这里我们再来看,如果我们在做设计的时候是先设计数据库表,然后使用ORM工具进行对象的映射(或者是先写类的属性,然后再映射到数据库,其实这两者都是一样),那么你真正做业务逻辑,需要持久化保存的时候,就不得不去考虑数据库的表结构以及他们之间的关系影响,甚至需要构造复杂的事务。就算这道关被咬牙坚持了下来,但由于数据库表结构的固定,必然会造成大量DTO在业务逻辑中的传递,很自然就出现了性能问题。
所以最后很自然,先有对象再映射到数据库才是使用ORM的正途。任何东西都有自己的生命周期,对象也是。从一个对象的生命周期,即对象被创建或者被从数据库中取到内存中,进行完复杂的业务逻辑运算,到最后消亡,这之中需要ORM的就是取对象到内存以及消亡之前的持久两个阶段。所以关于ORM性能的判断就决定于这个地方:我们知道一个对象通常会有关联和聚合,缺少了任何一个都会造成对象信息的不完整,所以ORM在构造SQL的时候必须要把这个对象的关联和聚合都要表示出来,而有些时候业务逻辑根本就不关心它的关联和聚合,于是大多数ORM组件都提供了一个LazyLoad的机制来提高性能。但是这一点也是ORM的反对者们所吹捧的一个性能杀手。那么究竟是怎样的一个情况,我没有自己实验过,不敢妄下结论。但从我阅读过的资料上来看,ORM加缓存并不比传统方法慢,有时候甚至要快上几倍。
这样肯定有人会问:如果我的需求改变,那么我的对象模型改变了,数据库岂不是也变了?咋一看确实没错,但是值得注意的是面向对象的设计原则中有一条所谓的开闭原则:类的设计要对扩展开放,对更改关闭。所以一个设计的符合面向对象5原则的模型应该是可以做到不用去修改已有系统的代码而满足变更的需求。这样一来,我们不过是需要在原有的数据库基础上新增几个表而已。
所以我个人对ORM的理解是只要你建立了对象模型,并采用关系数据库作为你的持久存储器,那么你就需要ORM,而不管你是用已有的组件还是自己实现。从这个层面上来说,什么该用ORM还是不该用ORM根本就是一个设计问题。如果从模型开始,不用也得用;如果是从数据库表设计开始,用也是没用。
参考资料:
1. 当前java项目开发中的几个误区
2. Why OO+多层结构?