`
cm4ever
  • 浏览: 5187 次
  • 性别: Icon_minigender_1
  • 来自: 广州
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

沉重的负担-Hibernate的反模式

阅读更多

前言

虽然Hibernate作为最早流行的轻量级ORM,java社区的头号杀手应用,给数据库软件开发带来极大的便利和影响,但是在长期的实践中,仍觉得有些场景比较笨重,使用起来不甚顺手,遂发发牢骚。

 

本文意在抛砖引玉,如果你也有类似牢骚和解决方案,不如也发出来共享一下。

 

虽然本人有能力解决这些问题,也提到了以前开源的扩展模块,但并非刻意宣传,因为对第3个模式的不满致使我决定放缓对hibernate的修改,除非有外力支持,比如所在公司支持或者网友支持。

 

题外话,我正在抽空写以COM、XPCOM为基础的orm,语言是C++。COM可以实现反射功能,恰好用来写ORM,成品可以供支持COM的开发工具使用,也可以在js中使用,js中的orm不是梦想,当然各大论坛有些网友说用纯js写orm也是个可行的办法,确实值得一试,不过访问数据库的组件还是得用c/c++之类的来写,这个跑不掉。

反模式1:不支持模块化

像struts,可以将Action配置写到其他xml文件,然后再struts-config.xml里引用这些xml文件达到模块化的作用。

问题场景1:

当多个开发人员同时将几百个mapping标签写到hibernate.cfg.xml里面,而且还在不断增加的时候,文件冲突就是家常便饭。

建议解决方案:

直接修改hibernate,2年前俺在hbn-dyn-mod的第2个功能就这么做来着,但是经常加班加到熊猫样,还是业余时间搞的,又没有得到领导的支持,而且hbn-dyn-mod第1个功能开源后没什么人反响,所以连在sourceforge上更新的热情都没了,最后,连硬盘里的代码都丢失了...

 

问题场景2:

Hibernate.cfg.xml经常改动,在cvs,svn经常update,如果数据库名称和密码不同,可有得受了...

建议解决方案:

手工改改。

或者先读取hibernate.cfg.xml到内存中,从其他文件获取本机的数据库名和密码,并修改到内存中的hibernate.cfg.xml,然后再用修改后的内容启动Configuration,这样一劳永逸。

 

反模式2:不支持延迟加载映射文件

本来某段时间只专注一个模块的开发,但是做个单元测试也要等全部xxx个映射文件加载完毕,时间和内存消耗让本就不多的系统资源捉襟见肘,他就没有选项支持直到调用Session.get, load, save, createQuery.list等api时才读取对应的.hbm.xml吗?这也就算了,要是其他模块的开发者上传了一个错误的.hbm.xml或者持久化类,那就连运行都免了...

 

建议解决方案:

暂时屏蔽出错的模块对应的Mapping标签。

另外Hibernate2的话,可以试试hbn-dyn-mod。

反模式3:两套DOM模型

Org.hibernate.mapping包里的类,在Configuration里使用,可以完整的对应.hbm.xml里所有的信息,到了SessionFactory,就只能拿到org.hibernate.metadata.ClassMetaData了,其他几个模型类分散到其他包里,而且还不提供SessionFactory.getConfiguration方法,也太绝了点吧...

而且ClassMetaData的用法我实在搞不懂,也懒得研究。

建议解决方案:

懒得想,直接修改源码,给SessionFactory添加getConfiguration方法。

 

反模式4:不支持动态重载映射文件和持久化类

这个要求高了点,见仁见智了,由于jvm的局限性,估计有些人因此而转向了更灵活的python或ruby。当然,我可以解决这个问题,8过正如开头所说的原因,现在对修改hibernate没兴趣。

分享到:
评论
12 楼 magus 2009-07-28  
简单MIS项目可以使用hibernate,但表格多的时候带来的内存开销很大。。在最早的项目中使用过hibernate,后来就没有用了。现在做的自己写的一个通用的范型DAO,使用JDBC实现,同时也支持hibernate实现、支持多个数据库。可支持配置文件,如果没有配置文件也是可以的,简洁方便。目前在使用中逐步完善功能,等功能比较完备之后在和大家分享
11 楼 eastone 2009-07-28  
我比较赞同我们一个老同事的观点:简单、直接。
框架可以借鉴,绝不使用。
10 楼 starffly 2009-07-28  
kjj 写道
引用

采用20多个库,每个库table很多有200多个,20个Configuration启动后占用了600M内存

20 个库 * 200 表 = 2000+表就算全部写在文件里,然后读到内存里,竟然占了600M的内存??,可以说说怎么算出来的吗

20*200=2000....
9 楼 timshaw9791 2009-07-10  
EXvision 写道
建议楼主认真学习hibernate。

对于第四点,在生产环境下,貌似这个完全用不上。
再说了新建了hbm.xml,还有相应的DAO、Service需要写,不重启服务就见鬼了。
每次都去搜寻一次更改效率更低吧。


我倒是期望能有一个按需加载的特性,金蝶自己搞的ORM里就有这个一个东西,比如说这次我load一个东西的时候和hbm里面定义的延迟加载有所不同,在加载A的时候需要同时将A.b也加载出来。不过初步意向这个东西可以通过封装一个HQL查询来实现。


另外,HQL不支持union等常见集合操作很郁闷,牛人总是抛出一句话,可以用sql来解决。。。

有人也提了好久了,到现在都没个说法,JIRA地址:
http://opensource.atlassian.com/projects/hibernate/browse/HHH-1050
8 楼 阳光晒晒 2009-01-12  
送你四个字:

单元测试.
7 楼 kjj 2009-01-11  
引用

采用20多个库,每个库table很多有200多个,20个Configuration启动后占用了600M内存

20 个库 * 200 表 = 2000+表就算全部写在文件里,然后读到内存里,竟然占了600M的内存??,可以说说怎么算出来的吗
6 楼 starfeng 2008-11-25  
1. 关于模块化问师, 现在已不成为问题.
引入属性hibernate.archive.autodetection即可.

2. 关于延迟加载, 这的确是一个问题.
做JUnit test时, 很浪费时间. 我想应有相应的改进方法.

3. 关于两套DOM模型, 这是合理的
你要更详细的xml里的信息, 可以从Configuration中取得, 运行时期, configuration对象被丢弃其实不完全是hibernate本身的错, 只不过是spring或ejb之类的容器没有提供这个configuration对象的引用.
ClassMetaData提供运行时间的对象信息, 和xml中的不完全相同, 这里可以获得运行期的sql,对象约束,关系等.
所以, 这两套模型都是有必要的, 针对不同用途.

附:
关于configuration对象的获取, 在03年,纯hibernate的时代,我们会new Configuration(),所以很易保存这一对象用于数据分析. spring引入后, 我们不会涉及这一块的处理, 可以如下方式取得:
1) 普通的hibernate方式, 让spring自动注入, 可以你的类中加入:
@Resource
private LocalSessionFactoryBean sessionFactoryBean;
然后用:sessionFactoryBean.getConfiguration()
2) JPA方式(或者说按EJB规范创建), 这个麻烦点, 如果没有jdni支持, 无法获得这一configuration, 需重载spring的HibernateJpaVendorAdapter,或者, 用Ejb3Configuration重新构建一个.

4. 关于动态加载和持久化
这个是一个成为一个专题了, 网上有不少第三方解决方案, 但都不是很完美, 我也奇怪为什么gavin king不在hibernate本身加强这一方面的处理. 难道他反对(或者不看好)动态OO? 事实上, 不少应用有这方面的需求.
5 楼 raymond2006k 2008-11-24  
ClassMetaData 的作用:

基本用处看它的的名字,就是获取映射类的相关元信息,如果你要进行元编程,很有用。
 
另一个用处在于它的子实现类: AbstractEntityPersiter,通常用来获取tableName。这个在我修改hibernate 一个 query cache 的bug时有用到。

 AbstractEntityPersister persister =(AbstractEntityPersister) classMetaDatas.get(entityName);			 
String tableName = persister.getTableName();


参考:
解决Hibernate SQL Query Cache的一个可靠性问题(附源码)

4 楼 raymond2006k 2008-11-24  
楼主说的问题,我在公司的项目中也深有体会。

3   不过第3点我比较赞同,因为时而发现hibernate的bug或项目中的特殊需要,需要修改源代码,去找相应的配置属性的调用方法要费九牛二虎之力,得分析sessionFactory,configuration等好几个类。

4  动态加载配置和映射,是一种热部署的思想,对于SOA架构,OSGi等也有这样的要求,我支持你;只是现在基于 xml 配置的方式,似乎厂商都不愿去动态化。

对其他问题,体会是一样的,特别是对于开发阶段,单元测试阶段,挺恼人的。

2  不过对于生产环境,第2点延迟加载配置可能有一定风险,还是要慎用,一次性加载便于发现错误的配置。


还有个问题,就是hibernate配置映射为的内存对象 Configuration, 极耗内存。可能一般的单数据库应用,table不太多的project,情况还不明显; 我们的移动项目,采用20多个库,每个库table很多有200多个,20个Configuration启动后占用了600M内存,1.5G的mx内存占了一大部分,很夸张!最后通过修改源码,采用共享机制得以化解。
结合 楼主的 第 2点,我觉得可以采用一次性全部验证, 而后采用Cache机制,内存中只维持最常用的一部分映射配置。


3 楼 EXvision 2008-11-03  
建议楼主认真学习hibernate。
第一点和第二点分明可以解决,何必抱怨hibernate不对,花点时间一找就搞定了。

另外个人认为:
“暂时屏蔽出错的模块对应的Mapping标签。”
是很扯淡的。

那请问需要在什么时候发现并解决错误?

对于第四点,在生产环境下,貌似这个完全用不上。
再说了新建了hbm.xml,还有相应的DAO、Service需要写,不重启服务就见鬼了。
每次都去搜寻一次更改效率更低吧。
2 楼 cats_tiger 2008-11-02  
LS说的对,用Spring可以解决部分问题。
第三点一般用不到;
第四点要求是高了。
1 楼 风花雪月饼 2008-11-02  
With Spring:

1.1 当多个开发人员同时将几百个mapping标签写到hibernate.cfg.xml里面,而且还在不断增加的时候,文件冲突就是家常便饭。
RE: mappingDirectoryLocations

1.2 Hibernate.cfg.xml经常改动,在cvs,svn经常update,如果数据库名称和密码不同,可有得受了...
RE: <context:property-placeholder location="classpath:jdbc.properties"/>使用${jdbc.driverClassName}取得值。



4....ruby在Product模式下似乎也还是要重启。

相关推荐

    DmDialect-for-hibernate1-5.zip

    达梦数据DmDialect-for-hibernate所有jar包,DmDialect-for-hibernate2.0、DmDialect-for-hibernate2.1、DmDialect-for-hibernate3.0、DmDialect-for-hibernate3.1、DmDialect-for-hibernate3.6、DmDialect-for-...

    DmDialect-for-hibernate4.0.zip

    本篇将详细介绍标题为"DmDialect-for-hibernate4.0.zip"的压缩包文件及其包含的两个重要组件:Dm7JdbcDriver17.jar和DmDialect-for-hibernate4.0.jar,以及它们在SpringBoot项目中的作用。 首先,SpringBoot是一个...

    spring-hibernate.jar

    spring-hibernate.jar

    DmDialect-for-hibernate5.3-5.3.jar

    国产达梦数据库hibernate方言包

    Middlegen-Hibernate-r5

    本文将深入探讨Middlegen-Hibernate-r5这一版本,揭示它们如何协同工作,为开发者带来便利。 一、Middlegen简介 Middlegen是一款基于Ant的任务,能够从数据库模式生成Hibernate的元数据XML文件,这些文件包含了...

    JavaEE源代码 spring-hibernate3

    JavaEE源代码 spring-hibernate3JavaEE源代码 spring-hibernate3JavaEE源代码 spring-hibernate3JavaEE源代码 spring-hibernate3JavaEE源代码 spring-hibernate3JavaEE源代码 spring-hibernate3JavaEE源代码 spring-...

    hibernate-extensions和Middlegen-Hibernate

    《hibernate-extensions与Middlegen-Hibernate:数据库到Java对象的自动化转换》 在Java的持久化层开发中,Hibernate作为一款强大的ORM(对象关系映射)框架,极大地简化了数据库操作。然而,手动编写实体类和映射...

    dao-hibernate.jar

    dao-hibernate.jardao-hibernate.jardao-hibernate.jardao-hibernate.jardao-hibernate.jar

    Middlegen-Hibernate-r5,hibernate-extensions-2.1.3

    【标题】"Middlegen-Hibernate-r5,hibernate-extensions-2.1.3" 涉及的是两个重要的Hibernate相关工具:Middlegen和Hibernate Extensions,这两个工具都是在开发基于Java的数据库应用程序时使用的辅助工具。...

    xjar-agent-hibernate-v1.0.0.jar

    xjar-agent-hibernate-v1.0.0.jar下载

    spring-hibernate3.jar.zip

    对于复杂的业务逻辑,Spring的DAO层和Service层设计模式可以帮助我们将数据访问逻辑和业务逻辑分离,提高代码的可读性和可维护性。 总的来说,"spring-hibernate3.jar"是一个便捷的集成解决方案,它使得Spring和...

    spring-hibernate 4个版本

    标题中的“spring-hibernate 4个版本”指的是四个不同阶段的Spring与Hibernate集成框架的版本。Spring是一个广泛使用的Java企业级应用开发框架,而Hibernate是一个流行的持久化框架,用于简化数据库操作。这两个库的...

    Hibernate-Extension Middlegen-Hibernate

    1. **安装配置**:首先,你需要下载并配置Middlegen-Hibernate的相关依赖库,如题目中提到的`hibernate-extensions-2.1.3`、`apache-ant-1.8.4`、`Middlegen-Hibernate-r5`和`hibernate-2.1`。Apache Ant是Java项目...

    达梦数据库java驱动包、hibernate方言包

    /*************************************** * 达梦8 JDBC驱动版本说明 /*************************************** ...8. DmDialect-for-hibernate5.3.jar 对应 Jdk1.7及以上, hibernate5.3 -- 5.4 环境

    spring-hibernate3.jar

    spring-hibernate3.jar 非常好用,请多支持!

    maven-hibernate3-jdk14-2.0.jar

    maven-hibernate3-jdk14-2.0.jar

    jackson-datatype-hibernate, 用于处理Hibernate的Jackson JSON处理器模块( http,Add.zip

    jackson-datatype-hibernate, 用于处理Hibernate的Jackson JSON处理器模块( http,Add 构建 Jackson 模块( jar ) 以支持JSON序列化和反序列化 Hibernate ( http://hibernate.org ) 特定数据类型和属性,特别是延迟...

Global site tag (gtag.js) - Google Analytics