爱的乐章,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, 可以维护复杂的对象关系。

ü         Hibernate的Query非常强大,几乎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(“agName1”);

//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很简单:拿公司常用的AG和AGGroup两个对象来模拟。

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

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

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

ü        测试用例:

将SN为1的AG的GroupID从“groupid1”改成“groupid2”

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

update AG set GroupID=”groupid2”where SN=1

2.2测试代码

Session session = HibernateSessionFactory.getSession();

session.beginTransaction();

//得到AGGroup对象

AggroupDAO aAggroupDAO = new AggroupDAO();

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

//得到SN为1的AG对象

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却执行了4条SQL语句!

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

2.4结论

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

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

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

3第三乐章:爱很简单

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

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

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

3.1测试用例

继续引用前面AG和AGGroup的用例。

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

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

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

ü        测试用例:

将SN为1的AG的GroupID从“groupid1”改成“groupid2”

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

update AG set GroupID=”groupid2”where SN=1

3.2测试代码

Session session = HibernateSessionFactory.getSession();

session.beginTransaction();

VmmAgDAO aVmmAgDAO = new VmmAgDAO();

VmmAg aVmmAg=aVmmAgDAO.findById(1L);

//更新属性字段

       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的实现原理之后,选择一种折中的实现方式,以期达到易用性和性能上的综合最佳。

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

爱的乐章,Hibernate之三部曲相关推荐

  1. 春节英语祝福【中英文对照】

    Safe trip wherever you go 一路顺风 Wish you happiness and prosperity in the coming year! 祝你新的一年快乐幸福 Wish ...

  2. 泰戈尔诗集-飞鸟集单词释义

    O Troup of little vagrants of the world, leave your footprints in my words 世界里成对的小小漂泊着啊,在我的文字里留下你们的足 ...

  3. postgresql 吕宏庆_吕宏庆:用网络汇聚爱心 用行动传递温情

    原标题:吕宏庆:用网络汇聚爱心 用行动传递温情 他热心公益,数十年如一日,奔波在志愿服务的道路上:他的生活并不富裕,却用微薄的收入帮扶孤寡老人和贫困学生:他对公益事业的执着,感染着身边的每一个人.他就 ...

  4. 难得和你相遇,用来生气多可惜

    有一天,我坐在回家的公车上,乘客很多.一对上班族男女恰巧站在我身边,吸引了我的目光. 可能因为人多,男孩将手臂围挡在女孩的腰上,怕后面的人挤到了她,并轻声地问"累不累?待会想吃些什么?&qu ...

  5. 七夕的简易代码表白合集

    一个小小的提问? 今天是2022年的8月2日,距离七夕只剩下俩天.作为程序员群体中的一员,你们准备好了吗? 话题: 每个人在人生的旅途中总会被在不经意间贴上了特定的标签.医生:救死扶伤:警察:英勇无畏 ...

  6. 《爱在 ZStack Cube 超融合》三部曲

    一.始于初识:很高兴见到你 这一天东川路最靓的仔打开了 ZStack Cube 宝盒 ,这可能是我们的第一次相遇,我们相谈甚欢,相遇恨晚. 我的名字是 ZStack Cube,一个基于超融合架构的云平 ...

  7. Hibernate, 想说爱你不容易

    2019独角兽企业重金招聘Python工程师标准>>> 见: http://www.blogjava.net/yoda/archive/2008/05/05/198488.html ...

  8. schema类SpringMVC+Hibernate+Spring整合(二)

    这段时间笔者几篇文章介绍了改schema类的文章. 关联文章的地址 这篇接着上篇,把没贴完的代码写完,上篇主要实现了一些公共配置和界面的东西,这篇把后台的代码实现. 首先是web包下属于的contro ...

  9. java 实体类包含list 怎么取值_舅舅是面试官,偷偷告诉你们面试官最爱问的Java面试题...

    2015 年,因为工作岗位的变动,舅舅开始负责给集团招聘一些技术人员,出于对公司的负责,也为了更好的胜任技术经理的职位,在面试的这件事上,舅舅做了大量的"功课",首先研究了几乎所有 ...

最新文章

  1. python 报错 IndentationError: expected an indented block SyntaxError: invalid character in identifie
  2. mysql self join_mysql self join的实现--left join 和inner join
  3. CSP认证201312-2 ISBN号码[C++题解]:简单题
  4. 使用JavaScript调用aspx后台代码
  5. 一起谈.NET技术,发布NGuestBook(一个基于.NET平台的分层架构留言本小系统)
  6. Retrofit与RXJava整合
  7. Java笔记-AnnotationConfigApplicationContext在Spring中的例子
  8. kubernetes集群应用部署实例
  9. ipad上linux终端,如何使用iSH在iPad或iPhone上获取Linux Shell
  10. MySQL内核月报 2014.10-MySQL· 捉虫动态·binlog重放失败
  11. 用maya怎么做ak47_串串香应该怎么用配料才能做得好吃
  12. java 面单模板_顺丰电子面单JSON请求格式
  13. c语言get获取数组参数,C语言访问数组元素
  14. linux重装显卡驱动后黑屏,manjaro系统用msm更换显卡驱动失败后黑屏的处理
  15. python extract_convert.py对应代码解读抽取式提取+生成式提取摘要代码解读------摘要代码解读1
  16. 三菱Q系列PLC基本指令讲解
  17. 今宵多珍重(珍藏绝版精选)铃声 今宵多珍重(珍藏绝版精选)手机...
  18. Golang源码探索----GC的实现原理(6)
  19. python numpy 获得数组的行和列(三种方法)
  20. Head Above Water

热门文章

  1. 【MQ笔记】聊一聊空间(线性空间、赋范空间、度量空间、内积空间、欧氏空间、酉空间)
  2. excel画图如何添加图表数据参考线
  3. 如我提升自我学习能力
  4. python数据结构基础(单链表,多链表,二叉树)
  5. 金色css颜色代码大全,CSS颜色代码大全
  6. AnnaAraslanova/FBNet 程序分析
  7. 开心,终于突破 1000 啦
  8. 孤岛危机 教程:使用Voxel技术创建地形
  9. 通讯录二维码使英文变为中文
  10. 在服务器上一按l键自动退出,利用 SysRq 键排除和诊断系统故障