`
robbin
  • 浏览: 4836343 次
  • 性别: Icon_minigender_1
  • 来自: 上海
博客专栏
377a9ecd-1ea1-34ac-9530-9daa53bb2a7b
robbin谈管理
浏览量:138034
社区版块
存档分类
最新评论

谈谈Hibernate令人不爽的地方

    博客分类:
  • Java
阅读更多
对于Hibernate,有两点值得反思:

1、HQL创造出来一种语言,目的是以对象方式类SQL去查询数据库,但是为什么不像rails那样,干脆直接定义COC让数据库schema 和对象的schema吻合在一起呢?这样,SQL不就是直接变成了对象查询语言了吗?缺点就是放弃更多更复杂的对象映射模型。但是我的经验表明,项目中要尽量避免复杂的对象映射,这样性能很糟糕,也很容易出错,实际上我仅仅只用n:1就可以表达很多种映射模型了。化繁为简,大巧若拙实为最高境界。

2、现在极其厌恶Hibernate生成的SQL,又臭又长,极难阅读。
分享到:
评论
32 楼 tomcat 2006-09-16  
lszone 写道
我在做项目的时候一般是native SQL 和 HQL混合使用,如果比较复杂的SQL,用native sql比较容易调优,简单一些的查询就用HQL
我也是这么干的
31 楼 lszone 2006-09-16  
我在做项目的时候一般是native SQL 和 HQL混合使用,如果比较复杂的SQL,用native sql比较容易调优,简单一些的查询就用HQL
30 楼 wandou 2006-09-16  
最不爽的是这个。
http://www.iteye.com/topic/244
没想到hibernate性能这个差。
莫非hibernate3.1用了ejb?为什么速度这么慢?
如果这么慢的话,那对于压力比较大的业务,hibernate其实是不能用的。
29 楼 progame 2006-09-15  
ylt 写道
Readonly 写道

我同意Readonly的观点。如果不用hql,想实现数据库兼容就太难了。
举个例子,在很多手工录入的表格中都要记录录入时间/操作人/备注,我在java中使用date/person/comment来表示,可是java的关键字和sql的是不一样的,不同数据库也有各自的扩展关键字,上面那几个字段很可能就是某种数据库的关键字。用hql,我所有的查询语句就可以保持统一,切换数据库只需要修改mapping。实际上我写了一个自动根据数据库关键字修改mapping的类,这样连mapping文件也只需要一个。

实现数据库兼容并不象你想象的那么难。:)
我做的平台软件在多种数据库上测试过,包括:Oracle9(10),SqlServer2000,MySql4(5),PostgreSQL8,
HyperSonic。
操作包括CRUD,查询也有比较复杂的。
兼容数据库的步骤如下:
1)数据库DDL是要自行处理的。当然可以借助PowerDesigner的自动转换数据库功能,虽然也有bug,其实主要无非就是一些数据类型的转换,手写也可。
2)CRUD之字段类型。JDBC的PreparedStatement已经帮你将所有的字段类型都封装了,不需要为了插入日期型等数据调用数据库本地的函数,ps.setDate()即可。
3)CRUD之SQL语法。ANSI SQL标准虽然贯彻得不够彻底,但常用的语法的确得到了一致认可。比如,表的左外连接在Oracle8里只有a.field1=b.feild2(+)这种方式,但在Oracle9以后,都支持标准的left outer join on语法了。这种语法在上述5种数据库都得到支持。其他的别名的语法也支持良好。
我碰到的一个比较搞的问题就是SQLserver2000种删除语句不能给表设置别名,即不能delete from TABLE a where a.id=?,去除别名无问题。
4)结果分页。这个的确是我碰到的最需额外处理等问题。我就是参考了hibernate的方法解决的。
5)ID生成问题。不同数据库有各自优化的方式,也可以使用通用的方式。也参考hibernate。
6)其他问题。比如Oracle里的hierachical query(connect by语句)在其他的数据库可能没有对等的实现方式,此时无法对此特性跨平台了。



sql 2000删除时可以设置别名的delete a from table a where a.id = ?
安全起见的话还是需要加一个SQL处理的,毕竟函数 CASE这些也算基本查询了 但不同还是很大的
CRUD问题不大
28 楼 zingers 2006-09-15  
Allen的方法时新版本的吧,
那个版本开始的?
27 楼 LucasLee 2006-09-15  
AreYouOK? 写道
我现在觉得还是jdbc来的最直接,有什么问题无非就是调试一下sql语句。虽然有时候象是在干体力活,但是多花一分钟的时间写sql语句总比花一个小时去研究hibernate产生的奇奇怪怪的现象要划算。

我把potian举过的例子修改下,假设你对性能感兴趣:
那么通常下hibernate会批量更新,但是A情况下就不会,A情况下如果满足B条件,它又能批量更新,不过你不能用C功能,否则它又不行,你是不是很崩溃?最后你可能要花好几个小时终于弄清楚了这个小问题,那边用jdbc做事的早就做完了。

jdbc大家都会,所以相对于整个团队而言,jdbc程序的可读性很好。而hibernate这种东西太复杂,每个人的掌握程度都不一样。这样,当我阅读或者修改别人的hibernate代码的时候,如果他用到了我不熟悉的功能,那么我总是要先花时间了解一下这个功能,否则当我操作对象的时候,不知道hibernate在后面做了些什么奇奇怪怪的事情,心里太没底。或许你是高手,可是当团队里别人要修改你的程序的时候,他怎么办呢?

用最简单的方式解决问题,是很有道理的。


这个问题有意思。我有同感。
没出现ORM之前就会有人觉得直接写SQL丑陋;现在又会有人觉得用ORM麻烦。
这真是事务发展的规律啊。
JAVA不也面临类似的疑问么?

得到一些也要失去一些。什么也替代不了你自己独立的、因地制宜的、具体问题具体分析的判断。
26 楼 LucasLee 2006-09-15  
ylt 写道

我同意Readonly的观点。如果不用hql,想实现数据库兼容就太难了。
举个例子,在很多手工录入的表格中都要记录录入时间/操作人/备注,我在java中使用date/person/comment来表示,可是java的关键字和sql的是不一样的,不同数据库也有各自的扩展关键字,上面那几个字段很可能就是某种数据库的关键字。用hql,我所有的查询语句就可以保持统一,切换数据库只需要修改mapping。实际上我写了一个自动根据数据库关键字修改mapping的类,这样连mapping文件也只需要一个。


实现数据库兼容并不象你想象的那么难。:)
我做的平台软件在多种数据库上测试过,包括:Oracle9(10),SqlServer2000,MySql4(5),PostgreSQL8,
HyperSonic。
操作包括CRUD,查询也有比较复杂的。
兼容数据库的步骤如下:
1)数据库DDL是要自行处理的。当然可以借助PowerDesigner的自动转换数据库功能,虽然也有bug,其实主要无非就是一些数据类型的转换,手写也可。
2)CRUD之字段类型。JDBC的PreparedStatement已经帮你将所有的字段类型都封装了,不需要为了插入日期型等数据调用数据库本地的函数,ps.setDate()即可。
3)CRUD之SQL语法。ANSI SQL标准虽然贯彻得不够彻底,但常用的语法的确得到了一致认可。比如,表的左外连接在Oracle8里只有a.field1=b.feild2(+)这种方式,但在Oracle9以后,都支持标准的left outer join on语法了。这种语法在上述5种数据库都得到支持。其他的别名的语法也支持良好。
我碰到的一个比较搞的问题就是SQLserver2000种删除语句不能给表设置别名,即不能delete from TABLE a where a.id=?,去除别名无问题。
4)结果分页。这个的确是我碰到的最需额外处理等问题。我就是参考了hibernate的方法解决的。
5)ID生成问题。不同数据库有各自优化的方式,也可以使用通用的方式。也参考hibernate。
6)其他问题。比如Oracle里的hierachical query(connect by语句)在其他的数据库可能没有对等的实现方式,此时无法对此特性跨平台了。

25 楼 zhaoyifei 2006-09-15  
liuwangxia 写道
robbin 写道
2、现在极其厌恶Hibernate生成的SQL,又臭又长,极难阅读。
深有同感!
原因是要为表生成别名,还要为字段生成别名,而且当 SQL 只涉及到一张表的时候还要为表生成一个别名 this_,为每个字段生成别名 *_0_,浪费!
对了,那位热心人能将这个问题提交给 Hibernate 开发组试试看!




机器自动生成,而且还得考虑不能触犯到保留字(java sql 数据库自身),这样多的要求,还得易看!其实hibernate做得很好了,只是我们不知道他们所考虑的。
24 楼 Allen 2006-09-15  
hibernate.format_sql = true

如果想要仔细看Hibernate生成的SQL语句,将format_sql设为true可以很大程度地减轻痛苦……


再加上这个的话:
hibernate.use_sql_comments = true

个人认为 [可读性 + 可定位性] 会更好。

当然,这两个一起来的话也会造成SQL在console中显示的篇幅很大。例如:

/**
 * 以下是Hibernate在控制台中自动生成的log
 */

Hibernate:
    /* criteria query */ select
        this_.id as id88_0_,
        this_.flag as flag88_0_,
        this_.description as descript3_88_0_,
        this_.mobilizationDate as mobiliza4_88_0_,
        this_.recordId as recordId88_0_,
        this_.deptFromId as deptFromId88_0_,
        this_.deptToId as deptToId88_0_
    from
        Mobilization this_
    where
        this_.flag=?
    order by
        this_.id asc

Hibernate:
    /* load net.example.model.PersonnelRecord */ select
        personnelr0_.id as id91_0_,
        personnelr0_.flag as flag91_0_,
        personnelr0_.birthDate as birthDate91_0_,
        personnelr0_.deptId as deptId91_0_,
        personnelr0_.eduQualificationId as eduQuali5_91_0_,
        personnelr0_.firstWorkDate as firstWor6_91_0_,
        personnelr0_.gender as gender91_0_,
        personnelr0_.idNumber as idNumber91_0_,
        personnelr0_.nationalityId as national9_91_0_,
        personnelr0_.originDate as originDate91_0_,
        personnelr0_.politicalConditionId as politic11_91_0_,
        personnelr0_.socialRelation as socialR12_91_0_,
        personnelr0_.description as descrip13_91_0_,
        personnelr0_.jobPositionId as jobPosi14_91_0_,
        personnelr0_.jobTitleId as jobTitleId91_0_,
        personnelr0_.jobTypeId as jobTypeId91_0_,
        personnelr0_.personName as personName91_0_,
        personnelr0_.iconUrl as iconUrl91_0_,
        personnelr0_.officialFlagId as officia19_91_0_,
        personnelr0_.marriageFlagId as marriag20_91_0_,
        personnelr0_.personnelNumber as personn21_91_0_,
        personnelr0_.quitWorkDate as quitWor22_91_0_,
        personnelr0_.address as address91_0_,
        personnelr0_.cellPhoneNumber as cellPho24_91_0_,
        personnelr0_.email as email91_0_,
        personnelr0_.phoneNumber as phoneNu26_91_0_,
        personnelr0_.nativeLocation as nativeL27_91_0_
    from
        PersonnelRecord personnelr0_
    where
        personnelr0_.id=?

Hibernate:
    /* load net.example.model.Department */ select
        department0_.id as id81_0_,
        department0_.flag as flag81_0_,
        department0_.deptName as deptName81_0_,
        department0_.deptTypeId as deptTypeId81_0_,
        department0_.description as descript5_81_0_,
        department0_.deptNumber as deptNumber81_0_
    from
        Department department0_
    where
        department0_.id=?

Hibernate:
    /* load net.example.model.Department */ select
        department0_.id as id81_0_,
        department0_.flag as flag81_0_,
        department0_.deptName as deptName81_0_,
        department0_.deptTypeId as deptTypeId81_0_,
        department0_.description as descript5_81_0_,
        department0_.deptNumber as deptNumber81_0_
    from
        Department department0_
    where
        department0_.id=?
23 楼 robbin 2006-09-15  
庄表伟 写道
记得以前robbin还说过,Hibernate生成的SQL,非常的优化,效率极高,非JDBC顶级高手,勿须尝试写出比Hibernate更加好的SQL。

怎么现在就成了:“现在极其厌恶Hibernate生成的SQL,又臭又长,极难阅读。”?


Hibernate生成的SQL确实不错,这方面我承认,但Hibernate把表名,字段名都自作主张加上了别名,看起来太难看了,阅读起来非常不友好。
22 楼 ajoo 2006-09-15  
Readonly 写道
偶严重反对robbin对于HSQL的看法,如果没有HSQL的话,让偶回到过去那种写一个产品,要在N种数据库上调试不同的SQL兼容性,简直是噩梦啊。
COC就更没有啥话好说了,你完全可以给Hibernate加个COC plugin,只支持native PK,只支持1:N,只支持字段和数据库栏位同名。批评Hibernate不够自动化,就象批评手自一体的BMW比自动挡的KIA难用一样好笑...

Hibernate生成的SQL倒是没有啥感觉,因为基本上hibernate.show_sql都是false,只有很特殊的调试情况下,才需要打开这个参数去看生成的sql是怎么样的吧?

用jrc sql,价格便宜量又足。
21 楼 cznc 2006-09-14  
______
20 楼 myy 2006-09-14  
庄表伟 写道
记得以前robbin还说过,Hibernate生成的SQL,非常的优化,效率极高,非JDBC顶级高手,勿须尝试写出比Hibernate更加好的SQL。

怎么现在就成了:“现在极其厌恶Hibernate生成的SQL,又臭又长,极难阅读。”?


正所谓“此一时,彼一时”嘛, ,说来说去,还是个场景问题,性能 vs 移植性...
19 楼 庄表伟 2006-09-14  
记得以前robbin还说过,Hibernate生成的SQL,非常的优化,效率极高,非JDBC顶级高手,勿须尝试写出比Hibernate更加好的SQL。

怎么现在就成了:“现在极其厌恶Hibernate生成的SQL,又臭又长,极难阅读。”?
18 楼 ylt 2006-09-14  
Readonly 写道
偶严重反对robbin对于HSQL的看法,如果没有HSQL的话,让偶回到过去那种写一个产品,要在N种数据库上调试不同的SQL兼容性,简直是噩梦啊。
COC就更没有啥话好说了,你完全可以给Hibernate加个COC plugin,只支持native PK,只支持1:N,只支持字段和数据库栏位同名。批评Hibernate不够自动化,就象批评手自一体的BMW比自动挡的KIA难用一样好笑...

Hibernate生成的SQL倒是没有啥感觉,因为基本上hibernate.show_sql都是false,只有很特殊的调试情况下,才需要打开这个参数去看生成的sql是怎么样的吧?


我同意Readonly的观点。如果不用hql,想实现数据库兼容就太难了。
举个例子,在很多手工录入的表格中都要记录录入时间/操作人/备注,我在java中使用date/person/comment来表示,可是java的关键字和sql的是不一样的,不同数据库也有各自的扩展关键字,上面那几个字段很可能就是某种数据库的关键字。用hql,我所有的查询语句就可以保持统一,切换数据库只需要修改mapping。实际上我写了一个自动根据数据库关键字修改mapping的类,这样连mapping文件也只需要一个。

对ror我不是很了解。我想知道如果已有的数据库中有的列名是ruby的关键字,或者ruby中的字段名是sql的关键字,这个时候ror如何处理?

简单的方案确实能解决大部分问题,所谓的80/20原则。但是有的时候就是需要复杂的解决方案。间接层次越多,系统就越灵活,能解决的问题就越多。
17 楼 downpour 2006-09-14  
Readonly 写道
downpour 写道

我们肯定希望采用一句HQL解决问题,但是此时问题来了,当你试图做SELECT department, count(employee.id) FROM .....这样的HQL时,在Java端,发现没有一个合适的对象可以映射。

从OO的角度,其实可以在Department这个类中加一个employeeSize来表示这种业务场景。但是好像Hibernate无法去做类似的映射。而iBatis在这个方面却灵活的多。


给一个构建函数:
public class Department(Department d, Integer employeeSize)

然后写成这样:
SELECT new Department(department, count(employee.id)) FROM .....

不就OK了吗?


我尝试过这种做法,不过记得好像以前调试的时候Hibernate报错啊。啥时候再调一把。

不过如果类似的业务场景中,我总觉得用构造函数不是一个很好的做法。因为可能一个构造函数只能满足单一的业务场景,如果现在再来一个类似的业务场景,这个构造函数就无能为力了。
16 楼 Readonly 2006-09-14  
downpour 写道

我们肯定希望采用一句HQL解决问题,但是此时问题来了,当你试图做SELECT department, count(employee.id) FROM .....这样的HQL时,在Java端,发现没有一个合适的对象可以映射。

从OO的角度,其实可以在Department这个类中加一个employeeSize来表示这种业务场景。但是好像Hibernate无法去做类似的映射。而iBatis在这个方面却灵活的多。


给一个构建函数:
public class Department(Department d, Integer employeeSize)

然后写成这样:
SELECT new Department(department, count(employee.id)) FROM .....

不就OK了吗?
15 楼 Readonly 2006-09-14  
偶严重反对robbin对于HSQL的看法,如果没有HSQL的话,让偶回到过去那种写一个产品,要在N种数据库上调试不同的SQL兼容性,简直是噩梦啊。
COC就更没有啥话好说了,你完全可以给Hibernate加个COC plugin,只支持native PK,只支持1:N,只支持字段和数据库栏位同名。批评Hibernate不够自动化,就象批评手自一体的BMW比自动挡的KIA难用一样好笑...

Hibernate生成的SQL倒是没有啥感觉,因为基本上hibernate.show_sql都是false,只有很特殊的调试情况下,才需要打开这个参数去看生成的sql是怎么样的吧?
14 楼 YuLimin 2006-09-14  
liuwangxia 写道
robbin 写道
2、现在极其厌恶Hibernate生成的SQL,又臭又长,极难阅读。
深有同感!
原因是要为表生成别名,还要为字段生成别名,而且当 SQL 只涉及到一张表的时候还要为表生成一个别名 this_,为每个字段生成别名 *_0_,浪费!
对了,那位热心人能将这个问题提交给 Hibernate 开发组试试看!


在开发时用P6Spy来拦截一下,就可以得到最终的SQL语句了啊,而且不要修改一行代码,只要更改一下配置即可。
当然你也可以结合SQL Profiler或IronTrack SQL来进行图形化的显示并进行性能调优,而且它们可以根据结果帮你生成索引脚本。
13 楼 JavaInActoin 2006-09-14  
还有一个严重问题:动态性。
字段的调整是比较常见的软件维护操作,
用上Hibernate后,这个功能就不太容易实现了。
字段的调节主要涉及三个地方:数据表、JAVA实体类、映射文件。
数据表的调整比较容易实现,而JAVA类、映射文件都不大容易在运行时动态更改,即使在运行时更改了、编译了,如果不重启,也不能正常工作。
现在能想到的办法只能是预留几个字段,以备不时之需。

相关推荐

    Hibernate入门到精通

    "Hibernate入门到精通" Hibernate 是一个基于Java的ORM(Object-Relational Mapping,对象关系映射)框架,它提供了一种简洁高效的方式来访问和操作关系数据库。下面是 Hibernate 的主要知识点: Hibernate 简介 ...

    Hibernate,hibernate笔记

    Hibernate 是一个开源的对象关系映射(ORM)框架,它允许Java开发者使用面向对象的方式来操作数据库。这个框架将数据库操作转化为对Java对象的操作,简化了数据持久化的复杂度。以下是对Hibernate的一些关键知识点的...

    hibernate显示不带?的完整sql

    综上所述,通过正确配置Hibernate的`hibernate.show_sql`、`hibernate.format_sql`以及日志框架的设置,我们可以得到不带问号的完整SQL输出,以辅助开发和调试工作。在实际项目中,可以参考上述步骤进行设置,确保你...

    hibernate 5.2.15

    hibernate 5.2.15 hibernate 5.2.15 hibernate 5.2.15 hibernate 5.2.15 hibernate 5.2.15hibernate 5.2.15

    Beginning Hibernate: For Hibernate 5

    - **Java 开发者**: 本书面向有一定 Java 和数据库经验但对 Hibernate 不熟悉的开发者。 - **对象关系映射**: 适用于希望学习如何在 Java 中实现对象关系映射的程序员。 - **新手入门**: 适合初学者快速掌握 ...

    Hibernate Spatial 4 教程

    Hibernate Spatial 4 教程 Hibernate Spatial 是一个基于 Hibernate 或 JPA 的空间几何对象数据库操作框架,提供了实现空间几何对象数据库操作的方法和配置说明。 一、 Hibernate Spatial 4 简介 Hibernate ...

    hibernate2 升级为hibernate3的需要注意的事项

    从 Hibernate2 升级到 Hibernate3 不仅仅是一次简单的版本迭代,它涉及到了多个方面的调整与优化。通过遵循上述步骤,开发者可以有效地迁移项目,利用 Hibernate3 的新特性来提升应用性能和可维护性。此外,在升级...

    hibernate关联映射详解

    hibernate,hibernate,hibernate,hibernate,hibernate,hibernate,hibernate,hibernate,hibernate,hibernate,hibernate,hibernate,hibernate,hibernate,hibernate,hibernate,包含4个说明文档,分别详细解说了hibernate...

    HIBERNATE 3.2 (1)

    HIBERNATE HIBERNATE HIBERNATE HIBERNATE

    hibernate jar包:hibernate-commons-annotations-4.0.1.Final.jar等

    Hibernate.jar包,Hibernate可以应用在任何使用JDBC的场合,包含 hibernate-commons-annotations-4.0.1.Final.jar hibernate-core-4.1.12.Final.jar hibernate-ehcache-4.1.12.Final.jar hibernate-entitymanager-...

    hibernate jar包程序文件

    hibernate-commons-annotations-4.0.1.Final.jar hibernate-core-4.1.12.Final.jar hibernate-ehcache-4.1.12.Final.jar hibernate-entitymanager-4.1.12.Final.jar hibernate-jpa-2.0-api-1.0.1.Final.jar ...

    hibernate3.zip 包含hibernate3.jar

    Hibernate3 是一个非常重要的Java持久化框架,它简化了数据库操作,使得开发人员可以更加专注于业务逻辑而不是数据库的细节。这个`hibernate3.zip`压缩包包含了`hibernate3.jar`,它是Hibernate 3版本的核心库,包含...

    Hibernate完整使用教程

    Hibernate 的创始人是 Gavin King,他是一名澳大利亚的软件开发者。Gavin King 于 2001 年创建了 Hibernate 项目,旨在提供一种简洁的方式来访问关系数据库。 POJO POJO(Plain Old Java Object)是 Java 语言中的...

    hibernate和MySQL的jar

    在描述中提到的“核心jar,亲测可用,跑demo是够用了”,这表明这些jar文件包含了运行Hibernate与MySQL交互所需的基本组件,并且已经有人验证过它们在演示或测试环境中可以正常工作。通常,这包括Hibernate的核心库...

    kingbaseV8 hibernate jdbc 驱动

    在Java开发环境中,与KingbaseV8数据库进行交互通常会用到Hibernate框架和JDBC驱动。 Hibernate是一个优秀的对象关系映射(ORM)框架,它简化了Java应用程序对数据库的操作,通过将Java对象与数据库表进行映射,...

    hibernate-release-4.1.4

    【描述】中的"hibernate的jar包"指的是Hibernate框架的运行库文件,这些JAR文件包含了Hibernate的所有核心API、实现和依赖库,如Hibernate Commons Annotations、Hibernate EntityManager、Hibernate Core等。...

    Hibernate3的依赖包

    10. **增强的性能**:通过延迟加载、批处理和缓存机制,Hibernate能够在不牺牲性能的情况下提供强大的功能。 在Eclipse中使用这些依赖包,你需要按照以下步骤操作: 1. **创建项目**:首先,在Eclipse中创建一个新...

    HibernateTools-3.2.4

    HibernateTools是Java开发人员在使用Hibernate ORM框架时的有力辅助工具集,主要目的是为了提高开发效率,简化数据库操作。在HibernateTools 3.2.4版本中,它包含了一系列的特性与插件,以支持更便捷地进行对象关系...

    hibernate5相关jar包

    例如,如果你的项目不需要JPA,就可以不包含`hibernate-entitymanager.jar`。同时,确保正确配置`hibernate.cfg.xml`或`persistence.xml`文件,指定数据库连接信息、方言、缓存策略等。理解并熟练使用这些jar包将有...

    Hibernate-Extension Middlegen-Hibernate

    《Hibernate扩展Middlegen-Hibernate:数据库到Java对象的映射神器》 在Java开发领域,Hibernate作为一种流行的Object-Relational Mapping(ORM)框架,极大地简化了数据存取操作,而Middlegen作为Hibernate的一个...

Global site tag (gtag.js) - Google Analytics