随笔 - 42  文章 - 71  trackbacks - 0
<2008年5月>
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567

常用链接

留言簿

随笔档案

文章分类

文章档案

搜索

  •  

最新评论

阅读排行榜

评论排行榜

俺是很老土的,由于项目需要,现在才开始学习Hibernate。其实Hibernate刚出来的时候,只是大概了解了一下,知道这是一个O/R Mapping的框架。但是具体怎么用,能够做到什么样子,没有一个具体的认识。现在从头学起,按照《Hibernate参考手册》提供的例子Step by Step做。做到Person和Event关联的时候,手册上给出的代码如下:

Session s = HibernateUtil.getSessionFactory().getCurrentSession();
s.beginTransaction();
Person p = (Person)s.load(Person.class, personId);
Event e = (Event)s.load(Event.class, eventId);
p.getEvents().add(e);
s.getTransaction().commit();

很简单,很优美的代码哦,看起来很OO。这个代码实现的需求也很简单,就是将一个Person和一个Event关联起来。

但是当我看到输出的SQL语句时就愣住了:

Hibernate:
    select
        person0_.id as id1_0_,
        person0_.age as age1_0_,
        person0_.firstname as firstname1_0_,
        person0_.lastname as lastname1_0_
    from
        T_PERSON person0_
    where
        person0_.id=?
Hibernate:
    select
        events0_.PERSON_ID as PERSON1_1_,
        events0_.EVENT_ID as EVENT2_1_,
        event1_.id as id0_0_,
        event1_.FIRE_DATE as FIRE2_0_0_,
        event1_.title as title0_0_
    from
        T_PERSON_EVENT events0_
    left outer join
        T_EVENT event1_
            on events0_.EVENT_ID=event1_.id
    where
        events0_.PERSON_ID=?
Hibernate:
    insert
    into
        T_PERSON_EVENT
        (PERSON_ID, EVENT_ID)
    values
        (?, ?)

 

姑且先不评价Hibernate生成的SQL语句的效率如何,就这个功能需求而言,映射到数据库上的操作就是在T_PERSON_EVENT表中插入一行。但是Hibernate却执行了3个SQL语句!如果只是在写一段Demo的代码,这样无所谓,但是如果是真的在有大量数据的生产系统上运行的话,我相信前面两个SELECT语句的消耗会比最后一个INSERT语句多得多。请不要对我说:可以在硬件上优化,可以在数据库进行优化。这个不是同一个问题。做为程序而言,应该是力求准确,该做的一样都不能少,不必要的就绝对不要做。其实无论是原来的结构化编程还是现在的OO编程,一个函数或者一个方法,都应该是做且仅作一件事,越靠近底层逻辑的地方越应该这样。尤其是在中国特色的系统中,典型的特点就是数据量大+业务复杂。在东北某省移动公司的BOSS系统,有几个主要的服务每天的调用量在3000万(每个服务,他们的服务器上有大概20个这样的服务)以上,在月底和月初的时候能够达到5000万甚至更高,但是服务的执行时间保持在0.02s-0.05s之间,这个当然和数据库设计和优化有关,但是我无法想象如果在一件简单的事情之外做一些不必要的事情会有怎样的结果。在南方的某移动公司,用户量已经达到3000万,他们的系统指导思想就是:用最简单的技术去做最复杂的事情。

Hibernate的拥护者会说,O/R Mapping的框架降低了程序员的门槛,不用去熟悉SQL。难道HQL就比SQL真的简单很多么?再说了,SQL是必须的基本功,就好像能够熟练使用操作系统是每个程序员的基本功一样。因为现在成熟的主流数据库都是关系型的,这是根本。这也是为什么O/R Mapping的框架运行起来总是很奇怪一样,因为从根上是关系型的,要想转化成OO,必然就有一些很别扭的东西。以上面的例子看,如果单纯看代码,都能够明白是要给Person和Event建立映射,不需要其它的东西,因为personId和eventId都已经有了。但是Hibernate不理解,他也没有办法理解。

有朋友说,使用Hibernate能够便于团队协作。其实团队协作也好,系统的可扩展性、可维护性也好,和你用不用Hibernate完全不相关。关键是看你的设计,能否清晰的层次化、模块化;管理上能否协调利用资源等其它因素。

 

我比较推崇WebLogic Workshop 8.1里面的Control/Database Control/Customer Control的设计思路(八卦一下,WebLogic Workshop的设计者之一来自MS,原来设计Visual Basic的,所以在Workshop里面有很多VBer熟悉的东西),直接在方法的上面用Annotation的方式编写SQL语句,支持命名参数。在编译之后成为无状态的Session Bean。自定义Control(可以认为是业务逻辑层)负责事务控制,很好用。

喜闻iBATIS也是这种思路的(自己写SQL语句),看来要学学iBATIS哦。

 

技术没有绝对的好与坏之分,只有适合与不适合之分。我觉得Hibernate并不是很适合大型、大量数据的、复杂数据关系的应用。如果我是客户,我需要的是一个准确满足需求,高效、稳定、易于扩展的系统,我不会关心你用的是什么技术(收费的东东另当别论,呵呵)。

以上是一个Hibernate初学者的看法,欢迎大家不吝赐教。

 

在google这个话题的时候,看到了另外的一篇帖子,和我的想法有点接近,原文在:http://www.jdon.com/jivejdon/thread/31879.html

作者drinkjava,内容抄录如下:

注: Hibernate的复杂性是人尽皆知,想问一下Hibernate的退化用法,在JAVA***上发过这个贴子讨教,http://www.java***.com/topic/82107
,可惜那个坛子高手太多,问题还没看清就开始挥大棒了,只好放这里了,顺便把它的一些回贴也贴在这里,望同好们指点一二:
我用Hibernate也有半年了,感觉Hibernate的映射关系太复杂了,与懒性加载,反转控制等结合在一起,要想控制好,实非常人之所能。个人感觉,如果不用Hibernate的关联,就把它当作关系数据库来操作,使用和理解上都会方便不少,例如一个订单和产品的配置文件写成这样:
<hibernate-mapping>
  <class name="db.Order" table="orders" catalog="sample">
    <id name="id" type="java.lang.String">
      <column name="ID" length="32" />
      <generator class="uuid.hex" />
    </id>
    <property name="orderTitle" type="java.lang.String">
      <column name="ORDER_TITLE" length="30" />
    </property>
  </class>
</hibernate-mapping>

<hibernate-mapping>
  <class name="db.Product" table="products" catalog="sample">
    <id name="id" type="java.lang.String">
      <column name="ID" length="32" />
      <generator class="uuid.hex" />
    </id>
    <property name="productTitle" type="java.lang.String">
      <column name="PRODUCT_TITLE" length="30" />
    </property>
    <property name="orderId" type="java.lang.String">
      <column name="ORDER_ID" length="32" />
    </property>
  </class>
</hibernate-mapping>

操作时:
Order o=new Order();
o.setOrderTitle("order1");
dao.saveOne(o);
Product p=new Product();
p.setProductTitle("product1");
p.setOrderId(o.getId());
dao.saveOne(p);
(HQL查询则仿照普通SQL中的写法,此处略)


这样一来,纯粹是用关系数据库的思想来使用Hibernate,一个类对应一个数据库表,表之间的约束交给数据库的键来控制, 这样一来,即得到了Hibernate的优点:不用手工写SQL,对象级别缓存,数据库可移植性,也不必费力地学习和理解它了,纯粹是一个薄薄的JDBC的包装; 缺点就是不能在HQL中写出"...object1.object2.object3..." 式的对象引用,而且关联表的加载要自已来维护,但我认为相对于理解它复杂的配置来说,这点牺牲还是值得的, Hibernate的高级特性当然没法用上了,但相比于直接用JDBC或用ibatis写SQL总要好得多,只要会关系数据库,就能立即上手,在新手多、工期短的项目中,可节省很多培训时间,而且对于后来维护者的要求也大大降低,请问我的这种想法是否可行?

以下为JAVA***上的回答
引用
java语言不是动态语言,简化不了这些操作。activeRecord给有我们非份之想,好像马丁大叔就在尝试做类时的orm框架。还有jruby给了我们可行的机会

drinkjava回答:答非所问,离题太远。
--------------------------------------

引用
不映射成类怎么利用OO思想啊,hibernate可以对一个对象进行操作,jdbc不行啊,主要是可以利用OO思想

drinkjava回答:你根本就没看明白这个贴子的观点,我的意思是完全不用OO思想,只是将Hibernate当作一个比jdbc顺手点的工具而已,我用关系数据库好多年了,也开发过上百个表的应用,不用OO不也照样做挺好?JDBC不行,可也没人说不准用JDBC吧?

--------------------------------------

引用
请再好好理解一下ORMapping的含义。
另外不能充分发挥关联关系的优势,是否是因为没有遵循“对象模型” -> “关系模型” -> “Hibernate映射规则”的开发顺序?
 

drinkjava回答:同上,不是我没理解,而是本来就没打算采用“对象模型” -> “关系模型”,而是直接一个表对应一个类,走的是"关系模型"的路子。

--------------------------------------

引用
不用关系影射,你用Hibernate干什么。

drinkjava回答:

咱笨,用不好关联映射,怕出错,所以干脆不用它,可关系模型咱还是很精通的,所有的关系就交给数据库去约束它好了。至于为什么还要用Hibernate,是相比JDBC和ibatis来说的:不用写很多SQL,有缓存,跨数据库,支持分页,Spring支持,总之好处一言难尽啊...

--------------------------------------

引用
性能上去了,面向对象特性没有了

drinkjava回答:

不知你是为了OO而开发,还是为了开发而OO

--------------------------------------

引用
我第一次用Hibernate的时候就是这么用的
然后涉及到多表连接时统统搞成视图

drinkjava回答:

不会这么恐怖吧?Hibernate很能干的,你google一下“hibernate多表查询”就知道了。

--------------------------------------

引用
我就这样用了快2年了,
非常的简便,门槛非常的低,效率也非常不错
级联查询统计返回object[]

drinkjava回答:

可见笨人不只我一个啊,这个居然用了2年。Hibernate的这种用法确实很另类,与它诞生的初衷可说是背道而驰,但事实上,这种方式程序跑起来绝对没问题,问题是这种用法能否被团队接受,让我用起来心里有个底,这才是我发贴询问的原因。光一个人私底下用,当然没人会来说三道四,问题是能不能引入到团队开发中,作为一种替代JDBC的简易方案,而不是被团队中的高手当作异已一棒子打死,因为通常一提到Hibernate大家就会联想到ORM,这确实是一个很容易陷入的思维惯性,事实上,前面几个回贴都是这样,也不想想贴子要表达的是什么,就开始反驳了。

posted on 2008-05-05 16:15 YODA 阅读(2867) 评论(23)  编辑  收藏

FeedBack:
# re: Hibernate, 想说爱你不容易 2008-05-05 17:12 大牙
呵呵~说得好~支持一下。我们之前一个BOSS项目,原来设计使用Hibernate,但是因为性能问题,到了中后期,除了使用单表维护,其他全部被JDBC替代。然后在另一个相对小型的项目中打算采用,开发了两个月,因为性能问题,被全盘弃用。重新走直接SQL的老路。
个人觉得,Hibernate只能在中小型系统中、或对于数据处理量要求较少的系统比较适用。  回复  更多评论
  
# re: Hibernate, 想说爱你不容易 2008-05-05 17:40 BeanSoft
Hibernate的一对一,一对多,多对多一直都是谨慎用为好,尤其是大表时候的效率很低。的确,iBATIS在做SQL为中心的项目时,更合适和高效一些。你说的那个地方我能猜到,那个地方高手很多,我发了个Netbeans Struts 2插件的使用视频发表,马上有人来说这插件如何如何不好,好像我是作者(遗憾的是我不是插件的作者),我就得把它做成世界一流,要负责一样。开源的软件嘛,大家都清楚就行了,有人给做个插件都不错了,不要搞的自己好像很热爱开源,主要目的就是希望开源的人就得做一流的插件出来,然后自己免费用,然后自己做不了还老指责别人,甚至指责写文章来推广它的人。国内的情况,大家还不都是拿着别人的东西(开源免费的和盗版的),自己一分不想花,完了还做东西来卖钱。  回复  更多评论
  
# re: Hibernate, 想说爱你不容易 2008-05-05 18:16 jejwe
iBATIS还是不错的。
毕竟myspace这个全球前几的网站用的iBATIS.NET.
我想java版本 的ib性能还是有保障的  回复  更多评论
  
# re: Hibernate, 想说爱你不容易 2008-05-05 20:23 26265
Hibernate做过两个项目,不稳定。后来弃用了,用JDBC自己写了一个类似的。  回复  更多评论
  
# re: Hibernate, 想说爱你不容易 2008-05-05 20:30 YODA
多谢各位给我更多的参考信息
BeanSoft,你知道我说的是哪里?哈哈,那你是不是参与了那里的项目了?  回复  更多评论
  
# re: Hibernate, 想说爱你不容易 2008-05-05 21:48 jacky-q
Hibernate,一开始省心,然后越来越不省心...  回复  更多评论
  
# re: Hibernate, 想说爱你不容易 2008-05-05 22:55 xiaohuasuper
你的文章不错,但你的blog太黑了,看不下去  回复  更多评论
  
# re: Hibernate, 想说爱你不容易 2008-05-05 23:02 YODA
呵呵,那我改一个,谢谢你的提醒  回复  更多评论
  
# re: Hibernate, 想说爱你不容易 2008-05-05 23:46 BeanSoft
呵呵 去注册了下 为了下东西 没参与什么项目 看来以后还是少注册点帐号 要不然徒增麻烦 呵呵  回复  更多评论
  
# re: Hibernate, 想说爱你不容易 2008-05-05 23:51 iday
把说明文档看完再说吧。。。。  回复  更多评论
  
# re: Hibernate, 想说爱你不容易 2008-05-05 23:54 sunlin
同意 我基本是这样想的  回复  更多评论
  
# re: Hibernate, 想说爱你不容易 2008-05-06 11:20 hammer
一片口诛啊!我也来添一口,我做日本和欧美外包项目,从来没听说过那个用Hibernate的。以前公司里技术经理也专门做过测试,Hibernate的性能在大型应用里确实比JDBC低好多。一般的做法是把sql放在一个xml或专门的class里,大家都来这里取着用。即方便查看,又可以在出了问题直接把sql粘到数据库客户端上运行看效果。对程序员来说,能直接看到sql是最放心的。  回复  更多评论
  
# re: Hibernate, 想说爱你不容易 2008-05-06 23:40 tianya
我觉得Hibernate很棒啊,提高效率是需要一些技巧的。一开始我也是像你们所说的那样使用简单的hibernate特性,后来在项目中不断探索,针对需要提高性能的地方着重进行优化,都能够很好的解决性能问题。
举个例子吧,我一个同事用SQL实现一个复杂的连接几个表的查询,数据量大的时候,需要花费数十分钟的时间。我使用Hibernate,再使用各种处理技巧(例如视图、分页、多线程、HSQL的优化、hbm.xml特殊处理)优化,实现的查询几乎能在半分钟之内显示结果。
  回复  更多评论
  
# re: Hibernate, 想说爱你不容易 2008-05-07 00:52 YODA
To: tianya
首先谢谢你的答复。不是说Hibernate就是不好,存在就是合理,Hibernate有他适用的地方。对于Hibernate的理解和掌握我肯定没有你这么深,我想表达的意思是,Hibernate可能无法准确理解程序对于数据操作的需求,所以做了一些无用功(要解决这个问题,估计还真是得参考drinkjava兄的Hibernate“退化”用法),所以我有点不喜欢它。说到优化,我也相信你说的实际情况,但是抛开数据库的优化不说,单纯的SQL优化要比HQL和Hibernate的优化可能更加明了和简单呢。就像上面Hammer说的,对程序员来说,能直接看到sql是最放心的。我就是为了放心...呵呵  回复  更多评论
  
# re: Hibernate, 想说爱你不容易 2008-05-07 11:05 Cchou
打算用这个东东的,现在开始犹豫了。没有升入运用过,不敢保证自己有这个能力去优化。  回复  更多评论
  
# re: Hibernate, 想说爱你不容易 2008-05-07 12:37 anonymous
就你这种水平,别处来现眼了  回复  更多评论
  
# re: Hibernate, 想说爱你不容易 2008-05-08 09:37 rain2005
不了解hibernate就不要用,真是浪费了!  回复  更多评论
  
# re: Hibernate, 想说爱你不容易 2008-05-12 15:14 lmj
Hibernate思想不错~~性能方面没有深入研究  回复  更多评论
  
# re: Hibernate, 想说爱你不容易 2008-05-29 13:12 碎石头
@tianya
"举个例子吧,我一个同事用SQL实现一个复杂的连接几个表的查询,数据量大的时候,需要花费数十分钟的时间。我使用Hibernate,再使用各种处理技巧(例如视图、分页、多线程、HSQL的优化、hbm.xml特殊处理)优化,实现的查询几乎能在半分钟之内显示结果。 "

如果你那同时花上你优化所用的一半时间来优化他的SQL,效率应该在你的一倍以上吧?  回复  更多评论
  
# re: Hibernate, 想说爱你不容易 2008-06-05 13:56 flybean
用这个例子来说Hibernate不好,不太合适。

所产生的前两句SQL,是为了获取Person和Event实例,并不是做“无用功”。
如果Person已经cache在本地了,则只会产生insert语句,换句话说,在INSERT之前的应该是已经存在Person实例了。

你所想的是在已知personID和eventID的情况下,将两者关联;而Hibernate所想的是关联已知的Person实例和Event实例。

作为ORM工具,Hibernate配合OO的JAVA,可以减少CRUD的工作量。但它并不能代替SQL语句。  回复  更多评论
  
# re: Hibernate, 想说爱你不容易 2008-06-05 17:50 YODA
感谢flybean回复

你说的很对,后来我也在想,未必是浪费,尤其是在B/S应用中,从使用户使用习惯和B/S应用的特点来看,可能做完INSERT还真的就是需要SELECT,Hibernate的这种特点就正好帮助我们做了这件事情了。呵呵

[作为ORM工具,Hibernate配合OO的JAVA,可以减少CRUD的工作量。但它并不能代替SQL语句。] 这个严重同意,很客观的总结。

再次感谢。  回复  更多评论
  
# re: Hibernate, 想说爱你不容易 2008-07-22 14:33 llmlx
好久没有看过Hibernate了。不过我印象中你提到的第二个sql语句是可以省略的。需要在one的一端设置inverse=true,many端设置inverse=false,也就是说将关系由多的一端维护。那样保存的时候,不是利用p.getEvents().add(e);而是通过e.setPerson(p)。我印象中是这样的,你可以尝试一下。到时候再告诉我一下结果。
对于Hibernate的使用我有一些体会,这个东西还是很强的,很多方面都考虑到了。但是,因为强所以很复杂,要想用得好必须要对其有比较深刻的理解,像延迟加载、缓存等。在使用之前一定要吃透官方提供文档和例子,否则还是用你有把握的sql语句,虽然复杂一些,但是不会有那么多麻烦。  回复  更多评论
  
# re: Hibernate, 想说爱你不容易 2008-12-11 23:22 benbear
至于效率问题,可以用缓存去解决。不能因为效率就去否定hibernate。毕竟它用起来很方便。  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: