总觉得Hibernate影响设计思路

玩hibernate有些日子了,但一直没敢在大型项目里用,主要是有种感觉:hibernate对设计思路有很大的干扰。

说个具体的例子:
很多应用都要求记录某一个业务对象的变更的历史,比如说,一个issue-tracking系统里,对issue的每一个处理步骤都要有纪录。这时,数据库通常设计为一个主表和若干个属性表,主表中保存业务对象不会变的属性,例如ID等等,属性表中记录经常更新的属性,两个表用主表ID相关联。若属性发生的修改,主表中不会变化,而属性表中会加入一个新的纪录,纪录中保存新的属性值、创建时间、创建人等等。

这样的设计应该是很常用的,但是若使用hibernate来实现,总觉得相当别扭。特别感觉OR-Mapping似乎对业务逻辑设计有很大的影响。比如:
理想的方法,应该是把整个业务对象表达成一个类(包括在主表中的属性和在属性表中的属性)。可是使用hibernate,如何做这种mapping?
如果把一些属性单独抽象成类,,这个属性类的实例作为主类的一个属性保存。这样对hibernate实现倒是简单了,只要一个one-to-many影射就好,但是这样业务逻辑表达上就严重不爽了。

不知道有没有DX处理过这类问题?

》hibernate对设计思路有很大的干扰
非常正确的感受,这就是数据库驱动设计和模型驱动设计不匹配引起的,因为你的习惯思路是数据库驱动设计思路,而Hibernate则是模型驱动设计思路,所以,你觉得有干扰,对抗发生了。

>应该是把整个业务对象表达成一个类(包括在主表中的属性和在属性表中的属性)。可是使用hibernate,如何做这种mapping?
这就需要使用到DDD领域驱动设计,首先设计出领域模型Model,然后再使用Hibernate等mapping工具将其持久化。

在你脑海中去除数据库设计影子,才能娴熟使用Hibernate这些为OO服务的框架,如果你的思维不是OO,当然干扰就会发生,问题出在你自身啊。

参考:面向ο蠓治`^程

strangecat20056M1NVeQg5v.png

我觉得不可能彻底的和数据库特型剥离。说一个具体的例子吧。背景看上面的图,基本上Issue类写成下面这样:


class Issue{
...
List issuePropPackList;

public IssuePropPack getCurrentIssuePropPack(){
}

public IssuePropPack getHistoryIssuePropPack(){
}


public List getHistoryPropPackList(){
}

}

那么,getCurrent/History IssuePropPack这两个方法如何写?标准OO应该是从List里面找,因为这是它的属性;但是实际上,估计多数人会用HQL直接查数据库,找两个PropPack--为了效率着想。


但是,使用HQL来找相应的实例,明显就是在设计实现中引入了数据库的概念了...

若你一定要勉强采用所谓OO,无疑是画地为牢。过分的强调OO,只会让你的设计变的呆板。怎么定义先进?倒觉得你应该仔细考虑这个问题。

> 若你一定要勉强采用所谓OO,无疑是画地为牢。过分的强调OO
> 换崛媚愕纳杓票涞拇舭濉T趺炊ㄒ逑冉康咕醯媚阌Ω米邢
> 考虑这个问题。

我正式觉得不能强往OO上靠,才会想讨论这个问题的。

把别人的方法论想透,或者理出属于自己的方法论,把事情想透了,用起来才有章法。

>我觉得不可能彻底的和数据库特型剥离。说一个具体的例子吧。背景看上面的图,基本上Issue类写成下面这样

这是一个一对多的关联关系,建立好这个模型后,当我们从Hibernate持久层获得Issue对象时(需要定义Hibernate的mapping的one-to-many关系),Issue的issuePropPackList集合已经有数据(可采取Open session in view提高效率)。

因此,业务层获得的Issue是一个完整的与数据库无关的完全OO对象;

如果不使用Hibernate,则在业务层和持久层之间封装一个工厂,专门来生产Issue对象,然后充实Issue的issuePropPackList集合属性,如果因为效率,可以考虑使用DDD推荐的组合模式(Respository)又被翻译成仓储,主要用来返回一批对象,查询组合常用来返回批量查询结果。

数据是从数据库获得,但是数据库的影响完全从业务层杜绝了,排除了在业务核心代码中随时出现的数据库访问,这样的代码肯定不能重用性;也反映程序员是在写流水帐,想到什么数据就从数据库取,很随意,这样的流水帐系统是毫无设计的,这样的系统有维护性和拓展性吗?

杜绝流水帐的编码,使用领域模型好好规划你的模型对象,将数据库阴影从业务层赶出去,这是DDD试图告诉我们的,这也是一个正确的OO系统应该做到的。

banq:
其实推而广之,我用的这个例子可以看出不少常用场景的影子,一个例子就是大数据量的浏览分页。

而你的思路恰恰是我不敢在大型项目里使用hibernate的原因:
系统构架设计的时候一个重要的地方是考虑负载的分配,哪些东西在数据库解决,哪些东西在应用程序里解决。比如,从一个List中选取一个特定的值,当然可以把数据都调进来,然后iterate中一个一个的判断查找,也可以直接用一个select语句,从数据库里直接把制定的结果选出来。显然,只有合理的分配负载,系统才能高效的完成功能。

但从你的思路中,全OO的一个潜在的意思就是让hibernate去处理负载的分配问题,自己的设计完全不进行考虑。这种想法在理论上显得漂亮,但实际用的时候,能保证效率吗?

>但从你的思路中,全OO的一个潜在的意思就是让hibernate去处理负载的分配问题,自己的设计完全不进行考虑。这种想法在理论上显得漂亮,但实际用的时候,能保证效率吗?

你的担忧是非常有道理的,其实使用Hibernate 的Open Session in View只有在真正遍历集合数据时才会读取数据库或缓存(如果二次以上是缓存),所以,在编程时我们回避了数据库,实现分层设计目的,而在运行时,它们是混合在一起运行的,这实际已经成为我们目前一个设计主概念,例如AOP等等都是玩这样的把戏。

如果理解这样的思路,我们来对付负载就有办法,因为首先负载是运行时的负载,根据上面运行原理得知,负载还是集中在业务层的Service上,这时我们讲这些Service使用集群性质的Session Bean实现,就解决了负载问题。

总之一句话:分而治之!

是设计要改变了,设计的过程不是一成不变的,和系统架构很有关系

在现代系统设计中,数据库影子基本看不见了。

大家可以查看开源软件的appFuse,在其中你都无法寻找到数据库SQL结构,甚至找不到Hibernate Mapping文件,它们都附属在Domain Model 对象中了。
https://appfuse.dev.java.net/

如果这么极端的例子无法接受,学习学习JiveJdon3,它也是一个DDD设计的案例,只是数据库使用了以前版本的,实现一个过渡衔接。

我是一个hibernate的反对者,我认为hibernate是技术牛人,架构笨蛋搞出来的东西(请宽恕我的无礼,我只想引起大家的重视).我曾经在我的blog上都批评了hibernate了几次。我现在总结一下我的观点:hibernate有三个理由我们不能觉得它是O/R mapping的企业化工具。
第一,它不符合人类的抽象思维,hibarnate是业务操作对象-->业务信息对象-->业务信息模型(xml的描述--实际上是DBMS逻辑数据模型)。本来从业务对象一下到了表关系就很大的问题,维护开发人员必须对相应的数据模型有必须了解后才能维护。维护的风险和成本都增加了。
第二,它回到以前的的数据库时代,如果不使用它的HSQL的话就完全否定了DBMS 的功能的时候是一个从业务代码抽象到数据对象的过渡(他隐藏了数据层面的业务抽象实现),这样的做法并不是说不好但是必须是你隐藏的如果能100%的满足和实现倒也是一个不错节省关注了一个层面,但是实践证明并非事事如愿的,恰恰是很多时候存在了这个DB层面业务对象(SQL)有了更合理的过渡。然而学习HSQL又是一种成本。我觉得SQL是DBMS提供出来一种面向对象抽象语言(准确的说应该是业务抽象语言)
第三,性能,如果不使用HSQL的话,性能在维护负责的多表的时候是困难和性能是低下的。
我觉得它和ibatis的比较,ibatis更像企业级东西。我blog上有我关于hibernate和ibatis的比较文章:http://recher.blogdriver.com/recher/1079673.html

这两天也在继续琢磨这个问题,思考出发点首先是怀疑:
是我自己没有学明白hibernate?还是hibernate本身有问题?

首先说自己的确对hibernate所知有限,毕竟一直没敢用它做大型项目,而只是玩了几个小例子程序。

但是有一点本质性的怀疑:
如果hibernate的引入真的能完全屏蔽数据库层,让开发人员完全从OO角度来构建应用,那么HQL拿来做什么用?

HQL是一个query language,和SQL层面类似。HQL引入进hibernate后,其实反而证明数据库层的东西是不能被完全屏蔽掉的!

所以我说hibernate就是一个技术狂给我们展现了一个例子:因为没有合理定位,没有把握住架构切入点,虽然有高超的技术,弄出来的东西反而是哭笑不得的东西(说他不好嘛,他在技术实现上的确有很多值得我我们学习,说它好嘛但企业级应用上又有一些对系统生命周期有害的东西)。我觉得它根本没有从O/R mapping在整个体系中正确定位(没有系统思考问题).还有我以前接触的项目有中型项目运用了hibernate,后果是大力理解和观看维护关系xml---也是一个很大的风险和成本。

HQL是object-oriented query language. Query是针对Domain object model的. 与你的relational model in DB毫无关系.
另外, 数据库的形式有许多种, relational, object-oriented, XML-native,berkeley database. 没有必要局限自己在relational db的框架之中.