爱的乐章,Hibernate之三部曲

爱的乐章,Hibernate之三部曲

 

摘要

本文介绍了笔者使用Hibernate的三个阶段。第一个阶段完全被Hibernate的优点吸引。第二个阶段发现Hibernate在性能上的一些缺陷。笔者通过实验的方式,证明了Hibernate的设计上的缺陷。第三个阶段,笔者基于性能以及简单设计原则的考虑,提出了一种简单使用Hibernate的方式,并用实验演示了这种实现方式及其优缺点。

 

关键词 Key Words

Hibernate  一个Java对象持久层轻量级封装框架

OO Object-Oriented,面向对象

O/R Mapping Object-Relationl Mapping,在关系型数据库和对象之间的映射

 

1第一乐章:糊涂的爱

1.1一见钟情

认识Hibernate,算来还在认识Spring之前。那是一个鲜见寒冷的冬天的一个下午,我对着电脑郁郁寡欢良久。外面的天空,刮着冷风,空气中弥漫着掀起的灰尘,似乎在映衬着我的心灰意冷。“冬天到了!”我在心里感叹,“如果我是一只熊,那多好啊,那样我就可以冬眠,而不用面对这烦人的冬天了!”

我感叹的何止是这天气,那是程序员的命运啊!几年前,我认识了高贵的Miss EJB 2.0,从此非常荣幸的加入了J2EE的豪门家族。豪门家族关系复杂啊,我花了好久才勉强适应过来。但是几年下来,我疲惫不堪,成天疲于应对家族里面那些莫名奇妙的怪人搞出的怪事情。后来我就开始和Miss JDBC约会。Miss JDBC来自一个孤儿家庭,家里就只有她一个人。同EJB 2.0比起来,JDBC拥有我最渴望的简单的社会关系。可是,JDBC也太孤独了,没有任何社会关系支持,什么事情都需要我去打理,生活的重担全落在我一个人身上。而与此同时,我发现Miss JDBC本人并不简单,脾气时好时坏,要处好与她的关系,必须牢记一些准则,这对我这个记性不是很好的人来讲,也并非易事。于是我开始觉得心灰意冷了......

我就是在这个下午邂逅Hibernate的。Hibernate轻舞飞扬的从我面前经过,轻轻的对我说,“程序员,别郁闷了,你现在就可以去冬眠,等到明年春天的时候,我来叫醒你!” 

那一刻,我明白了什么叫一见钟情。虽然对Hibernate不甚了解,但是我知道,Hibernate就是我心中的Miss Right !从此开启了和Hibernate爱的乐章。我发现,Hibernate有很多我钟意的优点。

1.2Hibernate的优点

Hibernate的优点很多,比如:

ü         Hibernate大大减少编程代码量,Hibernate把开发者从繁重的编码工作中解放了出来。

ü         Hibernate不依赖于任何容器,降低耦合,便于开发和测试。

ü         Hibernate致力于Java持久化数据问题的解决,封装了与关系数据库的交互。开发者的重心可以放在业务问题上而不是技术问题。

ü         Hibernate是真正的OO, 可以维护复杂的对象关系。

ü         HibernateQuery非常强大,几乎SQL能表达出来的逻辑,在Hibernate也能实现。

ü         Hibernate全部是本地调用。

ü        Hibernate沿用了传统数据库的Transaction编程模式,程序员可以控制事务,也可以交给Spring利用AOP的方式来管理,非常灵活。

对于一个从EJB2.0过渡过来的程序员,以上的特点有点让人想讲英文:

Fantastic! Amazing!

下面代码段是常见的Hibernate操作对象的方式,可以看到,没有SQL,是彻底的面向对象的持久化方式。

//new an Object,and set values

AG aAG = new AG();

aAG.setAgName(“agName 1” );

//get a Session,and begin Transaction

Session session =SessionFactory.getSession();

Transaction tx=session.beginTransaction();

//excute insert operation

            session.save(aAG);

//submit Transaction

tx.commit();

认识Hibernate不久,Hibernate的那种简单的OO操作数据库的方式让我放弃了整个ORM世界。告别了EJB,连其它诸如JDO/OJB/iBatis评价也不错的ORM产品,也不再我的考虑之中了。有成语曰:只见树木,不见森林。但我都已经见到了这么多树木了,我相信,我见到的就是一片不错的森林。

可能有点糊涂,可是自我感觉很良好!

 

2第二乐章:想说爱你不容易

人常曰:夜长梦多。随着时间的推移,我对Hibernate了解也越来越多。渐渐的我发现,Hibernate光鲜的外表下,有一个让我不可接受的缺点。

Hibernate内核其实是封装了JDBC,透明的实现了对象持久化到数据库的操作。这样,程序员就可以直接操纵对象,而不用关心对象是如何写入数据库的--因为Hibernate任劳任怨的包揽了这些苦力活。但与此同时,Hibernate的配置中提供了一个show_sql的选项,如果把这个选项配置为true的话,那么在控制台就可以打印出SQL语句。如此,我们就可以看到Hibernate是如何把我们的面向对象的操作“持久化”到数据库的。

人都有点窥探的心理。虽然Hibernate是开源的,可是我哪有时间去研究它?但是如果有机会花很小代价就能测试一下Hibernate的智商,那么还是非常Attractive的。

这个show_sql选项就属于我说的那种Attractive。我们可以根据这个选项,打印出SQL,再对比我们的业务逻辑,来看看Hibernate是如何设计的,看看它到底有多Smart?

2.1测试用例

Hibernate的猜想经历了一个比较长的过程,但测试一下却是一念间的事情,Case很简单:拿公司常用的AGAGGroup两个对象来模拟。

ü        类图:AG对象中有一个AGGroup对象的引用;

ü        数据库ER关系图:AG表有个GroupID字段外键关联AGGroup

有了类图和数据库ER图,我们就可以构造测试用例了。

ü        测试用例:

SN1AGGroupID从“groupid 1 改成“groupid 2

ü        对应的数据库操作SQL为:

update AG set GroupID=”groupid 2” where SN=1

2.2测试代码

        Session session = HibernateSessionFactory.getSession();

       session.beginTransaction();

 

//得到AGGroup对象

       AggroupDAO aAggroupDAO = new AggroupDAO();

       Aggroup aggroup = aAggroupDAO.findById("groupid2");

 

//得到SN1AG对象

       AgDAO aAgDAO= new AgDAO();

       Ag aAg =aAgDAO.findById( 1L );

      

//更新关系

       aAg.setAggroup(aggroup);

//很多程序员为了保险还会加下面这句

aggroup.getAgs.add(aAg);

      

//提交更新

       session.getTransaction().commit();

2.3测试结果及分析

控制台打印出来的SQL如下,总共有4条。

(1)Hibernate:

    select

        vmmaggroup0_.GROUPID as GROUPID0_0_,

        vmmaggroup0_.GROUPNAME as GROUPNAME0_0_

    from

        VMM.VMM_AGGROUP vmmaggroup0_

    where

        vmmaggroup0_.GROUPID=?

(2)Hibernate:

    select

        vmmag0_.SN as SN1_0_,

        vmmag0_.GROUPID as GROUPID1_0_,

        vmmag0_.DOMAINNAME as DOMAINNAME1_0_

    from

        VMM.VMM_AG vmmag0_

    where

        vmmag0_.SN=?

(3)Hibernate:

    select

        vmmags0_.GROUPID as GROUPID1_,

        vmmags0_.SN as SN1_,

        vmmags0_.SN as SN1_0_,

        vmmags0_.GROUPID as GROUPID1_0_,

        vmmags0_.DOMAINNAME as DOMAINNAME1_0_

    from

        VMM.VMM_AG vmmags0_

    where

        vmmags0_.GROUPID=?

(4)Hibernate:

    update

        VMM.VMM_AG

    set

        GROUPID=?,

        DOMAINNAME=?

    where

        SN=?

可以看出,前3条都是select语句,第4条才是我们想要的update语句。

从这个实验结果,聪明的程序员一下子就会看出问题:

就需求而言,映射到数据库上的操作就是在AG表中更新一条数据,对应一条Update SQL,但是Hibernate却执行了4SQL语句!

可想而知,如果在一些大量数据的生产系统运行的话,无谓消耗的这几条语句在性能上完全有可能造成系统崩溃。在事实面前,我不得不重新审视Hibernate,悲观之余想起了某牛人说过的话:“用最简单的技术去做最复杂的事情”。我有点怀念JDBC了。

2.4结论

固然,技术没有绝对的好与坏,只有适合与不适合。但本实验至少可以证明Hibernate并不是很适合大型、大量数据的、复杂数据关系以及对系统性能要求很高的应用。

真的是这样吗?难道就因为这样就要放弃Hibernate了么?HibernateOO操作数据库是那么的优雅,怎么能就这么轻易的放弃呢?

Hibernate,想说爱你不容易,想要放弃更不易。

3第三乐章:爱很简单

鄙人在学面向对象之前就一直同数据库打交道,所以对关系数据库有着莫名的感情。对系统而言,数据乃万物之本。往往看代码感到头痛的时候,看一下数据库,问题就明白大半了。所以无论业务逻辑怎么改变,一般来说,数据对象这些基本的关系是相对稳定的。因此,抓住数据库这个中心,是否可以对Hibernate的应用有些改善呢?

Hibernate的映射关系如果要仔细研究可以说是太复杂了,与延迟加载,反转控制等结合在一起,要想控制好,也需要下一番功夫。但是无论多么复杂,说到底也只是对ER关系的一个扩充。ER关系才是王道。至于延迟加载等特性带来性能上的提升,和本文第二章的实验证明Hibernate的最底层设计不够优化相比,则可以忽略不计,延迟加载至多也只是一定程度上的改善而已。

基于此,鄙人于是想大胆尝试一把:放弃使用Hibernate的关联,仅把Hibernate当作关系数据库来操作,是不是在使用和理解上都会方便不少,性能上也会提升很多呢?带着疑问继续做实验吧!

3.1测试用例

继续引用前面AGAGGroup的用例。

ü        类图:类关系去掉关联关系,AGAGGroup是两个独立的类。AG类中有一个属性GroupID,这个属性对应与数据库表的GroupID列。

ü        数据库没有任何改变:AG表有个GroupID字段外键关联AGGroup

从类图和数据库的改变可以看出,新的类图中去掉了关联关系,关系由数据库和程序来控制。

ü        测试用例:

SN1AGGroupID从“groupid 1 改成“groupid 2

ü        对应的数据库操作SQL为:

update AG set GroupID=”groupid 2” where SN=1

3.2测试代码

       Session session = HibernateSessionFactory.getSession();

       session.beginTransaction();

      

       VmmAgDAO aVmmAgDAO = new VmmAgDAO();

       VmmAg aVmmAg=aVmmAgDAO.findById( L );

//更新属性字段

       aVmmAg.setGroupid("groupid2");

       aVmmAgDAO.save(aVmmAg);

      

       session.getTransaction().commit();

3.3测试结果及分析

控制台打印出来的SQL如下,总共有2条。

(1)Hibernate:

    select

        vmmag0_.SN as SN1_0_,

        vmmag0_.GROUPID as GROUPID1_0_,

        vmmag0_.DOMAINNAME as DOMAINNAME1_0_

    from

        VMM.VMM_AG vmmag0_

    where

        vmmag0_.SN=?

(2)Hibernate:

    update

        VMM.VMM_AG

    set

        GROUPID=?,

        DOMAINNAME=?

    where

        SN=?

对比第二章Hibernate传统的OO方式和本章使用的新的方式,可以看出本章使用的新的用法有以下两个优点:

1)      SQL从4条减少为2条,性能应该得以大幅度提升。

2)      免去了复杂的对象关系,Hibernate只是一个简单的O/R Mapping工具。

3.4结论

  结论:将Hibernate看作一个简单的O/R Mapping工具来使用,一方面提升了系统性能,另外一方面,也将Hibernate的功能简化,使用其最核心最精华的O/R Mapping功能,降低学习成本,提高开发效率。

当然,我们同时也可以看出,这种解决方案在性能上亦并非是一个最优的解决方案。毕竟直接用SQL的话,一条update语句可以完成的操作,这种方式还是多用了一条select语句。对于对性能要求极其高的系统,采用JDBC或者HQL或许才是最佳的方式。本章讨论的这种使用Hibernate的方式是一种兼顾了性能和易用性的一种折中的最佳方式。

研究Hibernate的高级技术,到头来还不如简简单单的使用好Hibernate的核心技术来的更实用。此时,窗外突然飘来陶喆的那首经典歌曲《爱很简单》:

“没有后悔为爱日夜去跟随 那个疯狂的人是我

...

“用最真诚的心 让爱变的简单”

突然间,似乎一下子明白了爱的真谛所在――原来平平淡淡才是真,爱的真谛就是简单。

4.结束语

Hibernate的好,诚然是很好,它改变了我们传统操作数据库的方式,面向对象的操作,简单的配置,轻量级的架构,对容器没有依赖性...这些优点,信手拈来。但是技术再好,也要用的巧才算好,滥用可能会适得其反。对于系统性能有要求,对于程序架构简单维护有要求的系统,一定要找寻一种恰当的使用方式。

现在有很多技术都会有一个光鲜的外表,封装了很多技术,使用起来非常简单。Hibernate就是如此,封装了O/R Mapping的技术实现。如果不明白技术的实现方式以及关键技术细节,有时候带来的后果也不堪设想。好的封装只是证明易用性的提高,但性能上的减损作为程序员也需要加以重视。单方面的相信Hibernate会处理好这些问题,最后带给程序员的却往往是心灵的伤害。

本文提出的方式就是对Hibernate技术一个简单剖析,掌握了Hibernate的实现原理之后,选择一种折中的实现方式,以期达到易用性和性能上的综合最佳。

如果你也有类似的困惑经历,不妨一试,或许会有收获。

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值