Hibernate特点与思考

matrix 发表于 2005-12-21 07:10:12 作者:matrix;magicgod     来源:magicgod's blog
评论数:30     点击数:7,186

摘要:

magicgod昨天在他的blog上发布了一篇关于Hibernate的特点思考的文章,他提到了Hibernate的一些弱点:比如对象关系的映射配置过多,控制复杂;事务处理面临各种兼容问题;HQL语言增加学习成本等。并提出了一些减化和退化方案,具体请看下面的原文,你的建议又如何?
magicgod 昨天在他的blog上发布了一篇关于Hibernate的特点思考的文章。

他提到了Hibernate的一些弱点:比如对象关系的映射配置过多,控制复杂;事务处理面临各种兼容问题;HQL语言增加学习成本等。并提出了一些减化和退化方案,具体请看下面的原文,你的建议又如何?


Blog原文:

想了很长时间hibernate的一些弱点
1.对象与数据库的映射,关键在于对象关系的映射,但是没做到很理想,配置过多,控制复杂,另外还会出错。其实本质在于对象不够自由。

2.事务处理。这点上更容易出问题,相对于各种各样的事务管理器,要兼容是一个大问题,总归在各种应用服务器上有很多问题。其本质在于创建了一个自我数据存取小环境,必然面临各种兼容问题。

3.HQL语言。建立对象查询语言,类SQL,但是不同于任何一种SQL,调试环境复杂。本质在于创建了一种语言,增加学习成本。

减化hibernate,将其退化成一个sql生成器,既可以保留原有的主要功能,又可以兼容各种应用服务器和数据库服务器,另外还不需要学习HQL语言。

只需要一系列的功能函数,作一下包装,再根据不同数据库生成不同的SQL即可,连数据库类型都不用指定,因为从Connection中可以获得数据库类型属性。

假想中的API:

public Object ResultMapObject(ResultSet rs,String xml) //一行映射单个对象,可以用XML绑定,也可以不用。

public List SQLMapObjects(Connection conn,String []sqls,String xml)  //将一堆SQL映射成一个对象树,可以用xml来描述绑定,也可以不用,仅使用ror方式的约定。

借助JDBC和SQL可以构建整个数据存取层。

映射单个对象的代码,将一行记录映射成单个对象。sql可以是任意的。


    Connection conn=DriverManager.getConnection(url);
    PreparedStatement ps = conn.prepareStatement(sql);
    
    ResultSet rs = ps.executeQuery();
    while(rs.next())
    {
      user=(Users)ResultMapObject(rs);
      //TODO 可以使用user
    }


映射对象树。


    /*
    sale_orders销售订单表
    sale_order_details销售订单细表
    products商品表
    product_catalogs商品类别表
    从sql中就可以分析出
    id是主鍵
    sale_order_details.sale_order_id===>sale_orders.id
    sale_order_details.product_catalog_id==>product_catalogs.id
    sale_order_details.product_id==>products.id
     */
    String []sqls=new String []{
        " select id, total_sum, memo, state, modify_date, creator, checker from sale_orders ",
        " select id, sale_order_id, product_id, product_name, product_catalog_id, model, product_unit, product_amount, product_price, product_sum, memo from sale_order_details ",
        " select id, name, catalog, model, price, unit, memo, createtime, state, code, productno from products ",
        " select id, name, memo from product_catalogs"
    };
    //不帶XML映射的,但是無法得知一对一还是一对多还是多对多的关系,所以一律建成多对多关系。
    List l=SQLMapObjects(conn,sqls);
    /*
    l的结构:
    sale_orders[]
        |-----sale_order_details[](sale_order_details.sale_order_id===>sale_orders.id)
                |-----products[](sale_order_details.product_id==>products.id)
                |-----product_catalogs[](sale_order_details.product_catalog_id==>product_catalogs.id)                
     */


    /*
     带xml
     */


    /*
    sale_orders销售订单表
    sale_order_details销售订单细表
    products商品表
    product_catalogs商品类别表
    从sql中就可以分析出
    id是主鍵
    sale_order_details.sale_order_id===>sale_orders.id
    sale_order_details.product_catalog_id==>product_catalogs.id
    sale_order_details.product_id==>products.id
     */
    String []sqls=new String []{
        " select id, total_sum, memo, state, modify_date, creator, checker from sale_orders ",
        " select id, sale_order_id, product_id, product_name, product_catalog_id, model, product_unit, product_amount, product_price, product_sum, memo from sale_order_details ",
        " select id, name, catalog, model, price, unit, memo, createtime, state, code, productno from products ",
        " select id, name, memo from product_catalogs"
    };

    /*
<?xml version="1.0"?>
<MapObject>
<!--类似hibernate的映射,但是更容易理解,而且可以省略字段映射-->
    <Object tablename="sale_orders" class="org.test.pojo.SaleOrder">
        <OneToMany tablename="sale_order_details" class="org.test.pojo.SaleOrderDetail">
        <!--主细表映射-->
            <ParentKey>id</ParentKey>
            <ChildKey>id</ChildKey>
        </OneToMany>
        <!--字段映射可选,一般是相同或根据ROR规则-->
        <FieldMap>可选...</FieldMap>
    </Object>
    <Object tablename="sale_order_details" class="org.test.pojo.SaleOrderDetail">
        <!-- 附加代码表映射1对1关系 -->
        <OneToOne tablename="products" class="org.test.pojo.Product">
            <ParentKey tablename="sale_order_details">product_id</ParentKey>
            <ChildKey tablename="products">id</ChildKey>
        </OneToMany>
        <FieldMap>可选...</FieldMap>
    </Object>
    <Object tablename="sale_order_details" class="org.test.pojo.SaleOrderDetail">
        <OneToOne tablename="product_catalogs" class="org.test.pojo.ProductCatalog">
            <ParentKey tablename="sale_order_details">product_catalog_id</ParentKey>
            <ChildKey tablename="product_catalogs">id</ChildKey>
        </OneToMany>
        <FieldMap>可选...</FieldMap>
    </Object>
    <Object tablename="product_catalogs" class="org.test.pojo.ProductCatalog">
        <FieldMap>可选...</FieldMap>
    </Object>
</MapObject>
     */

    String xml="...";
    //带xml映射
    List l=SQLMapObjects(conn,sqls,xml);
    /*
    l的结构:
    sale_orders[]
        |-----sale_order_details[](sale_order_details.sale_order_id===>sale_orders.id)
                |-----products[](sale_order_details.product_id==>products.id)
                |-----product_catalogs[](sale_order_details.product_catalog_id==>product_catalogs.id)                
     */


当然类要事先写好,这里就不详细写了。

保存问题更严重,取出来用sql映射已经可以很好地解决了,基本上一个函数、一群SQL,加上少少的XML就可以表达清楚了,但是这不能解决保存对象的问题。

假想中的保存API。

public void saveObject(Connection conn, Object obj,String xml);  //保存单个对象,简单地将对象扩展成sql,允许xml映射,也可以不映射

public void saveObjects(Connection conn, List objs, String xml);  //将对象树保存到数据库

上一篇取出的List或人工组合的List可以用saveObjects来保存,这个函数的任务就比较重了,因为没有状态,所以要判断修改过非常麻烦。

一种思路是在对象是增加属性,然后由开发者维护,比如界面上是否修改很有可能是有状态位的,这个状态位就可以用起来,然后函数根据这个状态位来判断是否去更新。

一种思路是从Class本身中就得知对象是否被改过,类似AOP,在修改的时候记录一下,然后函数来判断是否改过,然后组成SQL来更新。

至于批量修改是强项,直接用SQL即可,学习SQL比HQL的成本要低,毕竟这么多年了。

外围实用函数的思考:基本上都针对SQL的生成,或数据库函数的替换

public String generateInsertSQL(DBType type,Object obj);//生成insert语句

public String generateUpdateSQL(DBType type,Object obj);//生成update语句

public String generateSelectSQL(DBType type,Object obj);//生成select语句

总之这个函数工具箱的思路有这几条:

1.使用函数,而不是使用环境来代替JDBC或应用服务器。

2.使用成熟的SQL,而不是自创语言,最多增加SQL预处理器,将一些函数转成数据库相关,简单的文本功能。

3.保持对各种环境的兼容性。对象是干净的,当然如果用AOP就很难说对象干不干净了,不过基本上应该适用于所有的环境中。

缺点:由于没有了环境,保存对象有点麻烦,用SQL来解决批量更新和删除,必要时增加几个SQL语句生成器即可。保存对象树是一个大缺点,没有非常好的办法能够将对象树整个保存下来而且效率非常高,只有上面提到的两种不太完美的办法,这都是因为JVM没有提供对象状态的原因。

不过这样用函数的方法来解决多继承的问题还是比较干净舒服的,既可以动态,又可以静态,随心所欲,灵活性、效率和兼容性兼得。

关注:
magicgod的Blog
Hibernate论坛

对此,你有何看法?


本页页面地址:

用户评论列表

#1 评论作者: lwqenter 发表时间: 2005-12-21 09:54 上午

谢谢楼上的,hibernate真的还有很多值得研究的地方啊

#2 评论作者: ginger547 发表时间: 2005-12-21 10:04 上午

虽然有这样的缺点那样的不足可是hibernate还是很强大的,试想不用它带来的困难是不是更多!

#3 评论作者: nightdress 发表时间: 2005-12-21 01:14 下午

的确是这样,但是就好像struts一样,用的群体还是大多数,短期之内还是主流!

#4 评论作者: rockingstorm 发表时间: 2005-12-21 03:50 下午 E-mail: rockingstorm@sohu.com

其实我是不用Hibernate,我干吗要学一个什么HQL,其实ORM不过是用了一个ResultSetMetaData,就是元数据,把一个表和一个类对象相联系,其实用Apache的dbUtil这个包就很好用,只要提供一个sql语句,还有定义好bean,就可以得回一个List,这已经足够了。

#5 评论作者: insecat 发表时间: 2005-12-21 05:07 下午

俺是农民,俺不懂啥叫hibernate。
俺只知道JDBC~
绝对灵活,绝对效率。

#6 评论作者: syxwxx 发表时间: 2005-12-22 04:37 下午

虽然现在他不是被人们所看好,但是在以后的发展与研究中,他的性能将一一表现出来

#7 评论作者: Jay.Ma 发表时间: 2005-12-22 09:10 下午

说实话,真正可怕的不是中国在IT技术上的落后,而是IT人乃至整个社会对IT思想的落后。有太多的人像楼上的那样,认为JDBC就够了,当然,这还是搞IT的;曾经我更被非IT的人问过我们java几十万元的系统和他们出2000多块钱让别人写的html网页有什么区别。我无法去和他说什么,不知如何说,和他谈技术他不懂,但我相信有人懂,所以软件业一定还能发展;可看了这里一些人,我觉得很心寒,他们自认为搞IT,他们懂一点技术,他们确不愿学习更先进的技术,更不愿去研究技术。看看世界上那么多FrameWork,有中国人设计、编写的么?再这样下去,也许中国永远只能跟着外国的技术走,中国程序员永远只能是廉价劳动力~

#8 评论作者: hibernate高手的工具 发表时间: 2005-12-23 05:32 下午

说实话,真正可怕的不是中国在IT技术上的落后,而是IT人乃至整个社会对IT思想的落后。有太多的人像楼上的那样,认为JDBC就够了,当然,这还是搞IT的;曾经我更被非IT的人问过我们java几十万元的系统和他们出2000多块钱让别人写的html网页有什么区别。我无法去和他说什么,不知如何说,和他谈技术他不懂,但我相信有人懂,所以软件业一定还能发展;可看了这里一些人,我觉得很心寒,他们自认为搞IT,他们懂一点技术,他们确不愿学习更先进的技术,更不愿去研究技术。看看世界上那么多FrameWork,有中国人设计、编写的么?再这样下去,也许中国永远只能跟着外国的技术走,中国程序员永远只能是廉价劳动力~

极赞同!
我在两个大型的项目中使用该ORM框架,工作效率大大提高,同时对系统架构设计和OOAD设计原则有更深入的认识了。

#9 评论作者: wyzok 发表时间: 2005-12-25 12:00 上午

说的不错。但是,如果hibernate本身也会做升级。说不定,下回hibernate升级时,会考虑这个映射的问题的。

#10 评论作者: marios 发表时间: 2005-12-25 08:40 下午

以上的三点还不是真正的问题.在我看来hibernate的缺点和它的优点一样
就是太灵活了.

#11 评论作者: APEX 发表时间: 2006-01-29 10:37 下午

说实话,刚开始研究HIBERNATE,不到3天的时间,但在我接触的第一天,我感觉HIBERNATE给我带来了黑暗中一丝黎明,真的。大家都加油吧,尽量赶上外国,不要被外国小看。

#12 评论作者: wdx04 发表时间: 2006-02-17 05:54 下午

回 Jay.Ma:
    首先,从纯技术的角度来说,Hibernate并没有什么值得骄傲的东西,C++的数据库 Framework 如 DTL 和 OTL 比 Hibernate 先进得多,它们也支持ORM,但不需要配置这一大堆的XML,C++的模板和运算符重载使得所有操作都很直观;Java方面,J2SE 5.0引入很多新特性,例如泛型机制、元数据等,提高了代码的可重用性和可读性,更使得Hibernate成了落后的技术。其次,国内外对于是否使用ORM框架一直有着激烈的争论,不要以为用JDBC就是不懂技术、不愿意研究技术。许多公司不用ORM框架,他们用自己的轻量级JDBC Framework,或者开源的iBATIS,Spring JDBC Framework,这些Framework比Hibernate更容易学习、更容易维护、更灵活,而且性能更高,还不像Hibernate这样挂着近10MB的第三方库,太笨重了。
    你的最后几句话让我感道很奇怪:“他们自认为搞IT,他们懂一点技术,他们确不愿学习更先进的技术,更不愿去研究技术。看看世界上那么多FrameWork,有中国人设计、编写的么?再这样下去,也许中国永远只能跟着外国的技术走,中国程序员永远只能是廉价劳动力~”。你用Hibernate,会写几个XML,就是在研究技术?Hibernate又不是你写的东西。自己不会思考,只会随大流,跟着外国的技术走,充当廉价劳动力,你自己正是典型。

#13 评论作者: JurnZhou 发表时间: 2006-02-18 12:39 上午

我是搞EJB的,hibernate真他妈烦。一大推xml,不看的人是聪明,看的并不代表你很有技术。CMP用工具Lomboz或Jbulder改一下服务器,重生发布一次即可。不过还是BMP爽,想干嘛就干嘛。给人绑手绑脚,你们不烦吖?

#14 评论作者: fight_bird 发表时间: 2006-02-28 11:23 下午 E-mail: fight_bird@163.com

偶然路过,发表一下拙见:
我曾经实践过很多持久层技术:JDBC、EJB、iBATIS、Hibernate、JDO、自定义JDBC框架、自定义ORM框架,确实感觉Hibernate是非官方标准的轻量级持久层框架中最强大的,但就国内的项目特点而言(外包、海外项目除外),Hibernate还是太“重”,学习成本和技术风险不比EJB低,在兼容性、AppServer支持力度方面还不如EJB,尽管所谓会者不难,但学习成本和风险对于国内项目来说十分重要,一般国内的项目特点可以归纳为三个字:短平快,即周期短、过程平、进度快,这些特点都不是Hibernate的优势所在。
个人觉得iBATIS才是国内项目最适合的持久层框架,它具有如下优点:
1、Apache的顶级项目(2005底加入Apache);
2、十分灵活、足够强大的Sql Map框架(不是相对复杂的ORM);
3、很低的学习成本,会Sql和Javabean足够了,没有什么新概念;
4、标准的轻量级框架,其DAO机制都是可选的;
5、出色的中文文档。
个人的经验:一个普通的Java程序员,只要懂Sql,2个小时内就可以熟练使用iBATIS处理大部分持久层任务,有点夸张?:-)
还有一点:iBATIS对简体中文用户的支持是非英语外的语言中最早的。
至于中国程序员的是否要原创、要创新,我的观点:拿来主义,我不觉得能有几个国内的程序员能设计出类似Hibernate的东东,这不仅仅是能力问题,还有大环境的问题,我们的软件发展还处于“初级阶段”,一个程序员拿什么资源来支持你自己的原创?
技术永远服从于商业价值!

#15 评论作者: lxw2008 发表时间: 2006-03-01 10:20 上午

hibernate,我是刚接触~~不敢说什么~~呵呵
看了大伙的评论`给我很大的触动~~谢谢~
中国的IT技术我相信会同当年的原子弹一样`
震惊世界的~

#16 评论作者: youway 发表时间: 2006-03-05 01:24 上午

我感觉作者是要把Hibernate变成iBATIS,呵呵

#17 评论作者: ChosenOne 发表时间: 2006-03-15 10:44 上午

各人认为Hibernate更适合于业务逻辑很明确,关系数据库设计已经很成熟的项目。在中国时常碰到需求分析不够或用户需求变化的项目,这时Hibernate的改动要比用SQL工作量大。

#18 评论作者: martin.guo 发表时间: 2006-04-10 02:08 下午 E-mail: gdq123@163.com

咳,不想用的别骂,大家心平气和的客观的谈论技术而已。

#19 评论作者: pig 发表时间: 2006-04-26 07:32 下午

哈。我也觉得hibernate不适合当前项目用,太烦琐,也可能是我悟性不够。丢脸了

#20 评论作者: mike 发表时间: 2006-04-27 09:33 上午 E-mail: mike_shanghai@163.com

我是初学HIBERNATE,觉得HIBERNAT的确太烦琐,还没原来的纯STRUTS好用呢,尤其提到的第三点,相当贴切,有了SQL何必再封装个HSQL,影响学习和开发效率,所以HIBERNAT的应用在我接触的领域里好象用的不多的

#21 评论作者: comeon 发表时间: 2006-04-28 07:58 下午

现在在学Hibernate,觉得初次上手是有点复杂,不过,熟了也挺顺手的,感觉现在大都在用hibernate,所以,没办法,只有多看看拉,欢迎大家共同交流,qq:49002149

#22 评论作者: plusir 发表时间: 2006-06-04 09:56 上午 E-mail: plusir@hotmail.com

按照我的理解,hql的作用是隔离数据库,防止应用对某一数据库产品产生依赖。我们公司的项目,平台部分全部使用的是hql,因为不同的项目部署时都需要挂到平台上,而这些不同的项目根据需求使用的数据库产品是不一样的,为了确保项目发布的时候不修改平台的持久化代码,所以没有使用原生sql。
另外,我觉得一个sql基础扎实的程序员,学习hql的成本不会太高。

#23 评论作者: 國中無後之山厓 发表时间: 2007-01-07 01:40 下午

hibernate確實又煩瑣又囉嗦,學習成本太高了。我自己寫了個簡單方便的持久層框架給程序員用,又快又好,沒有一大堆的XML配置文件,不用學習新的QL語句。
不要以為流行的就是好東西,我判斷是不是好東西,是不是好技術,唯一的標準是“簡單方便”。

#24 评论作者: rockingstorm 发表时间: 2007-01-25 09:28 上午

回 Jay.Ma:
   请问你看过那些ORM framework的源代码吗?似乎没看过吧,其实你如果看过你就知道ORM的核心就是如我说的:"其实ORM不过是用了一个ResultSetMetaData,就是元数据,把一个表和一个类对象相联系",只要会这个,你就可以写一个ORM framework 了,我不喜欢Hibernate,更因为我有自己的一套东西,还有建议你去看看一个framework :Mr. persist,我觉得这是比Hibernate好得多的框架.

#25 评论作者: 84zz 发表时间: 2007-02-01 11:37 上午

数据持久层的作用是明显的.....框架总是会进步..如果你想怎么样的东西他就能马上做出什么样的东西的话那软件就会越来越不值钱

#26 评论作者: zhangcheng 发表时间: 2007-02-27 09:23 上午

学了几天Hibernate我觉得情况并不是那么的糟糕!
Hibernate 还是优点多一点!
有些人说Hibernate麻烦,繁琐,但我觉得有很多人并没有真正理解Hibernate!!

#27 评论作者: ql213 发表时间: 2007-05-02 12:09 下午

最近开发一个项目,持久化层以hibernate为主,看了以上朋友的观点,自我觉得jdbc与hibernate并不矛盾,以前开发网站一直用JDBC,因为规模小,所以把灵活性作为首要目标,感觉用JDBC开发自由度非常大,但是缺少面向对象思想,代码不怎么规范和严谨;后来开始研究hibernate(PS:JDBC自我觉得应该先掌握,在此基础上学习hibernate),发现在学习hibernate的时候,我更多体会到的是一种良好的持久化解决方案以及MVC在此方案下的实现,同时这非常有助于对设计模式的深入发掘。当然不可否认,hibernate还存在一些不足,特别是在海量数据的检索以及对新的SQL查询技术的支持方面。所以,实际过程往往综合JDBC+DAO(看项目所需)。
最新的EJB3。0标准参考了hibernate,有机会可以好好钻研下!

#28 评论作者: xmlmail 发表时间: 2007-06-26 08:14 下午

感觉hibernate配置量比较大 但是有支持hibernate的插件 开发起来不是很麻烦 但是hibernate的分页遇到大数据量时,例如:查49999到50000之间的数据 速度慢   看了一下iBATIS 还是最适合我的 开发速度快 很好的中文文档  支持自己写的sql   不要用HQL

#29 评论作者: dhxyu 发表时间: 2007-07-04 11:10 上午

一个产品的形成与存在自有其道理!
何必呢?学习人家的设计模式和处理方法都是不错的!
【中国JavaEE技术交流社区】
www.j2eedve.com欢迎您的参与加入!


发表我的评论 (评论可增加个人积分...)

用户*: E-mail:
评论内容*:

支持BBCode
算术题*: + =