Hibernate设计得失分析

作为目前最成功的ORM系统,Hibernate获得了广泛认可。在此,我想就hibernate的设计初衷及其采取的策略做些分析,与大家共享。

 

个人觉得,hibernate的产生应该归结到面向对象领域,大家的目光由类逐步转到了对象这一大环境下。在这个大的环境影响下,产生了hibernate、spring、html、JavaScript等等一系列构建并管理对象的对象生存环境。在这一系列的对象生存环境中,持久对象的生存环境及构建方式有些特殊。

 

我们先来看看spring的对象是怎么构建的,spring中最常使用的对象构建方式是用xml文件,产生bean对象,如下:

 

<bean class="...">

... ...

</bean>

 

调用spring的bean工厂提供的获取对象的方法,就可拿到有特殊生存周期的对象,对象是由spring的bean工厂来管理的。对象的构建是依靠xml文件中描述的内容构建的。

 

然而在持久对象层,由于普遍使用关系数据库保存对象,对象实际是由关系数据库来创建并管理的。可是关系数据库并没有明确描述对象之间关系的方法,所以hibernate所做的第一件事,其实就是采用xml描述同一类对象之间关系。比如:我们可以如下换一个角度看hibernate所做的这项工作。

 

先按关系数据库思考,有两个表,一个班级表,有班级编号、班级名称等内容,一个学生表,有学生学号、学生姓名、学生所在班级编号等。从数据库里,我们无法获得班级的学生属性及学生的班级属性等对象之间的关联关系,所以,只能额外添加描述来表示这样的关系(不管是不是hibernate)。hibernate帮我们完成了这种关系描述,如下:

 

<class entity-name="clazz" table="clazz">

  ... ...

  <set name="students">

    ... ...

  </set>

</class>

 

<class entity-name="student" table="student">

  <many-to-one name="class">

    ... ...

  </many-to-one>

</class>

 

在上面的例子里,我采取了hibernate支持的动态实体方式,这种方式允许我们不写java类,就可以对对象进行操作。有了上面的配置,如果我们获得了一个班级对象,就可以直接访问到班级的学生集合了,如下:

 

Map clazz;

Set s = (Set)clazz.get("students");

 

经过上面的分析,我们理解了,其实持久对象的生存环境以及构建过程,已经利用关系数据库实现了,hibernate所做的,是通过xml方式的配置,让这些对象之间的关系暴露出来,方便按面向对象的方式访问这些对象。

 

接下来,怎么访问这些对象。hibernate采取的是利用java等现有语言访问。这难道还有疑问吗?有,而且疑问很大。这表现在接下来,hibernate3所作的增强,那就是批量处理中,bulk-update及bulk-delete。hibernate3所做的这两项增强,让我们在访问持久对象时,不再只有java语言一种方式,还有hql语言方式。比如,给3班所有学生分数加10分,可以用java语言如下操作:

 

Map clazz = (Map)session.load("clazz", 3);

for(Student s : clazz.get("students")) {

  s.score += 10;

}

 

上面的写法,不但罗嗦,而且效率极低。因为hibernate将被迫进行多次sql操作,才能完成上面的功能。采用bulk-update方式,执行下面的hql语句即可:

 

update student s set s.score = s.score + 10 where s.id in (select s.id from clazz c join students s where c.id = 3);

 

这条语句将被hibernate翻译成一条sql语句执行,效率高了很多。但是其可读性还不如java,我们在处理需求时,不得不转换思维,而不是按直接的需求方式书写。怎么会这样呢?这是因为不管是sql,或者模仿sql的hql,都不是真正的面向对象批处理语言。java虽然是面向对象处理语言,但是批处理执行能力太差。问题的根源是,我们需要一种面向对象的批处理语言。

 

比如上面的需求,面向对象的批处理语言可以如下写:

 

clazz[3].students { score += 10; }

 

上面的语句,我们可以翻译成hql或者干脆sql执行,效率与用bulk-update是一样的。而在可读性方面,比hql,甚至于java都清晰明白。

 

综上所述,hibernate很好的解决了存储在关系数据库里的对象关系描述问题,但在对象操作上,开始只提供java语言方式,后来追加了hql方式。如果性能不重要,那就使用java语言,如果性能比较重要,还是要使用hql语言的。对此问题比较彻底的解决方案,是提供一种面向对象批处理语言,更好的按面向对象的方式对对象进行成批处理。

 

对这种语言,我再举几个例子。

 

例子1:在某销售系统里,找出当月销售业绩小于前三个月平均值的销售人员。

 

var s = sales[sell[last].money < sell[last-3..last-1].avg(money)];

 

例子2:在学生管理系统里,找出1班分数不及格的学生及父母名字。

 

var s = clazz[1].student[score<60](name, father.name, mother.name);

 

例子3:在学生管理系统里,给1班所有分数超过80分的学生,添加一面红旗

 

clazz[1].student[score>80] { flag++; }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值