`
raymond2006k
  • 浏览: 291421 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

我的开发规范分享(二)- 禁用Hibernate HQL,QBC,QBE编程(1)

阅读更多

 

 

   【START 修改日志 当天 22:12 】:本文主要是针对基于Hibernate框架的项目开发中复杂查询的最佳实践。分析了前几个网友的意见,我想在几个基本方面hibernate QBC,QBE还是很方便的:

    1) 单表简单查询(基于字段的等值查询, 全部And运算)时,简单的汇总,如count等。

    2) 全动态查询条件, QBE很方便。

   【END 修改日志  当天 22:12 】

 

【START 修改日志 2008-9-19 21:20】:

   [quote="ziyuan"] ibatis完全符合lz的需求,,why not try it[/quote]

 

     同意你,我在公司项目中制定这个开发规范正符合 ibatis 的特点, 不过 Hibernate 对其也提供了完全的支持, 这两者在该功能上是一样的。

 

      因为 2006年项目启动时,已经确定使用 Hibernate 3, 而公司以前编程规范是使用 HQL, QBC 的 , 正好那次在项目初期对Hibernate 这一使用规范逐渐纠  正过来。

      如果是新的项目, 我想 ibatis 也是可以考虑的方案。
【START 修改日志 2008-9-19 21:20】

 

   

 

    2006年公司电信项目启动时,项目组选择沿用使用已久 的Hibernate及开发规范做 ORM方案。 做为公司新的电信项目的架构师一员,根据一直以来的项目经验,在项目进行2月后,面对复杂查询业务陆续增多,原有以Hibernate HQL,QBC 为特点的开发规范有些无法很好满足需求。

  

    因此在分析复杂查询业务 及 Hibernate 的特性特点, 我为 Hibernate 开发时制定了一个规范:禁用 HQL,QBC,QBE编程, 有三个要点,对于非单表的简单查询:

 

    1)程序员不得在Java代码中直接使用HQL;

    2)不得进行HQL拼装;

    3) 不得在 hbm.xml 映射文件中使用named HQL query。

 

    该规范按重要程度 基于四个方面的考虑:业务复杂度,程序员开发效率,维护难度和执行性能。  规范要求在 Hibernate 的 hbm.xml  文件配置Named SQL Query 来进行这些功能的开发。


    项目中我们对其进行了适当的易用性改造,关于我们项目中Named SQL如何具体应用,见下一篇分享:我的开发规范分享(二)- 禁用Hibernate HQL,QBC,QBE编程(2)

 

1. HQL,QBC:

    今天写这个分享短文,源于前几天回覆网友icewubin 的帖子: “一个关于Hibernate的优化实例:从HQL到QBC,从QBC到QBE,再到‘增强的’QBE”,主要是Hibernate查询的几种使用方式:HQL,QBC,QBE。

    先说 QBC,QBE,例如:(Hibernate QBC 示例代码)

 

public List<Product> getProducts(Product product) { 
final Example exampleProduct = 
Example.create(product). 
enableLike(MatchMode.ANYWHERE). 
excludeZeroes(); 

return (List<Product>) getHibernateTemplate().execute( new HibernateCallback() { 
public Object doInHibernate(Session session) throws HibernateException { 
Criteria crit =session.createCriteria(Product.class). 
add(exampleProduct); 
return crit.list(); 
} 
} 
); 
}

 

或例如:(Hibernate QBC 构造查询条件示例代码)

Restrictions.ne(propertyName, propertyValue);
crit = Restrictions.gt(propertyName, propertyValue);
crit = Restrictions.lt(propertyName, propertyValue);

 
 

2 ORM框架下复杂查询的处理

 

    几年前,我使用另一个ORM框架Ofbiz, 它的QBC,QBE与Hibernate类似,而且条件构造的类库更为完善. 当时使用过JDBC编程的我也对这种纯Java的,优雅的查询编程吸引,折服(当然这种思想确实是大牛们的伟大创新), QBC,QBE对单表,简单查询条件,两表关联查询支持很好.

 

    然而当项目设计完毕,进入开发阶段后,我们发现,这种查询开发模式遇到了瓶颈. 因为当时项目是财务系统,业务比较复杂, 多表关联查询,汇总查询,子查询等复杂查询陆续涌来. QBC,QBE的不足马上体现出现. 为此项目组对此类业务不得不用改用native sql来开发, 为与Ofbiz的ORM思想保持统一, 以配置sql为数据源的实体成为虚拟实体(Virtual Entity), 虚拟实体同样在映射文件中配置. 这个对Ofbiz的封装和改造,马上发挥用途,项目顺利,流畅的推进了。

 

3. 我们的项目规范:禁用 HQL,QBC,QBE编程

 

    回到我们的2006年启动的电信项目,使用的是Hibernate,它增加了HQL,以OO的方式写查询语句,也是牛人Gavin King的力作。但与Ofbiz类似,它对多表关联查询,汇总查询,子查询,三者混合查询的支持依然不足。作为新任架构师经过对公司之前架构规范分析,及一番思考,决定使用Hibernate时的一个规范:禁用 HQL,QBC,QBE编程。

 

    在项目开发规范中,我对这个规范进行了要点分析和总结。

    HQL,QBC开发的缺点:
    1) Java代码和查询语言混合开发,没有分离,易读性,维护性差;
    2) HQL编写和调试困难,对于较为复杂的查询,通常需要转化为SQL进行调试,调试完毕又要转为HQL,转换过程需要对HQL有较好的理解,但容易出错,开发时间长;
    3) QBC 编码量多,开发慢,易读性,维护性差;
    4) HQL,QBC功能有限,前面提到的多表关联查询,汇总查询,子查询,三者混合查询支持不佳或无法支持。相信朋友们都遇到过类似的需求。

    5) 还有一个考虑就是性能问题,有的HQL被Hibernate内部组装为SQL后,可能存在性能隐患,如果修改的话比较麻烦。

 

4.  复杂查询的解决方案

   解决方案仍然是,在hbm.xml 文件中配置named sql query。Ibatis 也有类似功能。

 

例子1:查询指定模块的所有下级模块, Hibernate 能将查询结果自动和 ModuleVO 映射起来

 

<!-- 查询指定模块的所有下级模块 -->
	<sql-query name="system.module.queryAllSubModules">
			select  module.MODULE_CODE as MODULECODE,
                       module.MODULE_NAME as MODULENAME,
                       module.MODULE_TYPE as MODULETYPE,
                       module.PARENT_CODE as PARENTCODE,
                       module.MODULE_DESC as MODULEDESC,
                       module.MODULE_URI  as MODULEURI,
                       module.MODULE_VIEW as MODULEVIEW
			from 
			(
			select t.child_code, t.offset from sys_module_rela t
			where t.ancestor_code = :parentCode
			) m1 join sys_module module
			on m1.child_code = module.module_code
			order by parent_code, module_order
	</sql-query>

 

 

例子2:以判断操作员是否对某个URI有访问权限为例, 返回值 val 大于0时表示有权限:

<sql-query name="system.perm.hasURIPermisson">
    <return-scalar column="val" type="java.lang.Integer"/>
   select count(1) val from sys_module module ,
   (   select distinct p.module_code from sys_oper_perm op , sys_perm p
    where   op.oper_id = :oprcode and op.perm_code = p.perm_code )  op
   where
   module.module_code = op.module_code
   and  module.module_uri = :currentURI
</sql-query>

 

我们项目中的Java代码的调用就更为简单了:

/**
  * 检查指定工号对 web请求 uri是否有权限。
  * @param oprcode
  * @param currentURI
  * @return
  * @throws Exception
  */
 public boolean doCheckURIPermission(String oprcode, String currentURI) throws Exception {
  PermDAO dao = (PermDAO) DAOFactory.build(PermDAO.class,user);
  
  Param param = new Param();
  param.getQueryConditions().put("oprcode", oprcode);  //设置固定参数 :oprcode

  param.getQueryConditions().put("currentURI", currentURI); //设置固定参数 :currentURI

  Integer count = (Integer)dao.queryUniqueByNamedSqlQuery("system.perm.hasURIPermisson", param);
  return count.intValue() > 0;
 }

 

而如果使用HQL,估计很难实现;

使用QBC查询,至少需要2-3步,代码较多,并且可能或查出冗余数据, 影响应用性能。

 

named sql 的优点和上面HQL,QBC的缺点正好相反:

    1) Java 代码和查询语句分离,易读性好,维护性好;
    2) 使用原生 SQL 开发,调试简便。如果是oracle,在pl/sql中进行调试,修改快捷而高效;
    3) 原生 SQL功能自然不必说,它是最全的。复杂的业务如果它都支持不了,那就得歇菜了。
    4) 充分发挥 DBMS 本身特定sql 语法的特性。

 

 5. 跨数据库问题

    在和网友icewubin 的讨论中,有一个问题值得说一说:跨数据库问题。他的意思是使用HQL,QBC可以保持数据库通用,这是他们的项目需求。实际上,我们当初的项目也是要求跨数据库的。解决方法是,针对Oracle,DB2,Informix等客户可能用到的db专门做sql调整, 也就是有两个DB的 sql 实现,(当时为新客户调整到DB2 sql,也就花了一周时间)。
    这个方案与Oracle BPEL等产品一样,例如:改产品出厂时,有针对不同数据库的DDL脚本文件,一个道理。

 

6.  Named SQL在我们项目中的具体应用。

 

    我们对其进行了适当的易用性改造,关于我们项目中Named SQL如何具体应用,要工作了,呵呵。下一篇分享文章,再聊. 我的开发规范分享(二)- 禁用Hibernate HQL,QBC,QBE编程(2)

分享到:
评论
37 楼 yanghuw 2008-09-23  
<p>简单查询HQL,复杂查询sql-query<br/></p>
<div class='quote_title'>upheart 写道</div>
<div class='quote_div'>很想知道,如果一个查询条件是动态的,比如根据用户输入的查询条件来构造,那这种方案怎么做?</div>
<p>    动态条件可以通过Where子句来判断条件,比如你需要查询订单,订单号的条件是可选的,你可以在查询语句中这么写:ORDERNO is null OR o.ORDERNO=:ORDERNO,这种方式和if-else一样,如果条件为空就判断下一个条件,不为空就比较条件,就是效率会稍微差一点</p>
<p> </p>
<p> </p>
36 楼 piggy 2008-09-23  
看完所有贴,基本上都是跟着lz反着唱的,楼主在回复的时候已经说明了,是有前提条件的,在这样的前提条件下,选择是比较少。我所知道的,电信定下的数据库,基本上不会换。

顺便说一下,我们项目使用ibatis。
35 楼 Gavin.Chen 2008-09-22  
   能不用SQL就不用SQL,这一年来,我己深深理解到数据库无关的查询语言所带来的便利与好处了,如果以后还要换数据库,有你好受的。

   存储过程?还没遇到非用不可的情况,能不用就不用的情况倒是很多,在本人经手的其中一个项目里,由于是许多年前的项目,有好几百个Sybase的存储过程,现在我们的团队正致力于将全部存储过程抛弃,改为java + EJBQL实现,配合Subversion,项目管理得非常流畅,程序员也写得舒心,如果用存储过程,写个两千行的SQL,写的人跑了,换个人去改点点逻辑,看你死不死,再加上存储这玩意怎么配合版本管理?想请教请教一下大家?

    如果为了快,电信企业想买几台服务器我看都行,搞个分布式,想有多快就有多快,没必要以牺牲代码的可维护性为代价吧?想不通!莫非电信的都是看代码的高手?我看八成也是耐力与眼力超强型!

    用Hibernate的HQL或EJB的QL写多级复杂查询?是不是有点把HQL当SQL的升级版来使用了?
34 楼 raymond2006k 2008-09-22  
EXvision 写道
恭喜lz将hibernate成功转变成ibatis。
不会用不要瞎用。
ibatis适合你。



大牛老兄,如果你教条的认为用 HQL,QBC 才是 Hibernate 正统, 用 Named SQL Query 就不是在用 Hibernate ,那我也没话说,哈哈。

或者你个给个 Hibernate下 复杂查询的解决例子吧。
或者谈谈你所谓的“不瞎用”吧。

33 楼 EXvision 2008-09-22  
恭喜lz将hibernate成功转变成ibatis。
不会用不要瞎用。
ibatis适合你。
32 楼 raymond2006k 2008-09-20  
Norther 写道
建议楼主的标题改为“不熟悉hibernate还要硬上hibernate的开发规范分享(二)- 禁用Hibernate HQL,QBC,QBE编程(1)”



无需改。 大家理解不同,项目经验不同。
31 楼 Norther 2008-09-20  
建议楼主的标题改为“不熟悉hibernate还要硬上hibernate的开发规范分享(二)- 禁用Hibernate HQL,QBC,QBE编程(1)”
30 楼 pdw2009 2008-09-20  
我认为电信级别的项目不适合用hibernate,新手用好hibernate可不是件容易的事,一个项中开发规范和技术架构很很重要.
29 楼 raymond2006k 2008-09-20  
tibetjungle 写道
weizh 写道
其实就是禁用hibernate,还这么复杂搞个禁用HQL。像生成报表之类的复杂查询,我想JDBC都不适用。

对,我们系统现在使用的100多个报表,现在都用存储过程做。一方面是业务规则比较复杂,一方面是考虑复杂的sql在效率方面会有问题,而且难以优化。



最佳实践有多种,Store Procedure 也是一种我们以前使用过的方式,而且Hibernate 对此也是支持的。如果能充分结合 Hibernate Cache功能,这也是一个不错的方案,只要你们定下一个规范就可以了。

28 楼 fireflyc 2008-09-20  
我恰恰相反,我认为使用hibernate要尽量使用HQL。
对于复杂查询我们引入jdbctemplate就可以了。
27 楼 tibetjungle 2008-09-19  
weizh 写道
其实就是禁用hibernate,还这么复杂搞个禁用HQL。像生成报表之类的复杂查询,我想JDBC都不适用。

对,我们系统现在使用的100多个报表,现在都用存储过程做。一方面是业务规则比较复杂,一方面是考虑复杂的sql在效率方面会有问题,而且难以优化。
26 楼 碧海山城 2008-09-19  
面对复杂的查询,或者说关联的表稍微多一点,hql生成的sql就会有半个屏幕,确实感觉不是很舒服啊
25 楼 raymond2006k 2008-09-19  
duobin3000 写道
看了你的帖子,我有点莫名的郁闷,你都做到了架构设计了,难道还不了解hibernate和原生sql的关系吗?
他们解决问题的方式是不同的:
hibernate:一方面是让你用OO的思想去思考问题 ;另一个方面是说我不是为了优化sql,而是采用缓存,提高命中率,减少DB的访问
而SQL,不一样,它是面向DB的,优化SQL等方式提高DB的性能,这个是他的职责。
从这个文章来看,电信真是烂




  话不要说这么绝对。Named SQL Query本身也是Hibernate 的一个特性,千万不要将它和  Hibernate 对立起来。 (这是我 2006 年确定的 Hibernate 使用的规范。)

  如果你面对的是新项目,你这样说完全 OK。
  如果是一个 2006年 已经确定用 Hibernate 的项目, 在项目初期遇到复杂查询业务,不知你会怎样处理开发和选型的问题? 

  在理论 hibernate 和 sql 有你所说的区别; 但在实际项目中, 你可以看看情况是怎样的;你只看到 sql 面向DB,而没注意业务的复杂性; 我不相信你只用 Hibernate 的 OO 在一个项目里就能搞定所有业务需求。

   还是感觉很多朋友只是教条的坚持每个技术的标准特点和规范,不能做适当变通。

   本文分享出来,正是给使用 Hibernate 的兄弟提供一个实践经验的参考。


24 楼 raymond2006k 2008-09-19  
ziyuan 写道
ibatis完全符合lz的需求,,why not try it


   同意你,我在公司项目中制定这个开发规范正符合 ibatis 的特点。

   因为 2006年项目启动时,已经确定使用 Hibernate 3, 而公司以前编程规范是使用 HQL, QBC 的 , 正好那次在项目初期对Hibernate 这一使用规范逐渐纠正过来。

如果是新的项目, 我想我会选 ibatis 的。


23 楼 duobin3000 2008-09-19  
看了你的帖子,我有点莫名的郁闷,你都做到了架构设计了,难道还不了解hibernate和原生sql的关系吗?
他们解决问题的方式是不同的:
hibernate:一方面是让你用OO的思想去思考问题 ;另一个方面是说我不是为了优化sql,而是采用缓存,提高命中率,减少DB的访问
而SQL,不一样,它是面向DB的,优化SQL等方式提高DB的性能,这个是他的职责。
从这个文章来看,电信真是烂
22 楼 raymond2006k 2008-09-19  
melode11 写道
用named sql query还用什么hibernate...

另外,hibernate的文档中提到了,hibernate是对并发处理非常好的框架,在[高并发]和[合理使用]的情况下,性能可以达到jdbc的水平。



named sql query 本身也是 Hibernate 的一个的特性。
21 楼 weizh 2008-09-19  
其实就是禁用hibernate,还这么复杂搞个禁用HQL。像生成报表之类的复杂查询,我想JDBC都不适用。
20 楼 fuwang 2008-09-19  
rockjava 写道
fuwang 写道
我要抛弃hibernate,决定用ibatis之类的东西了。
不是hibernate不好,而是hibernate太深了,我玩不转,我觉得我再用几年也精通不了。
要做一个让人放心的业务系统,需要对hibernate非常熟悉,把hibernate用好才能做出来。
看看周边的情况,基本都是菜鸟在用 hibernate,做了几年的菜鸟在教新手如何用hibernate。
老板、售前、实施、项目经理都在叫:不就是增删改查吗?要有多简单就有多简单!


hibernate就是个错误?是菜鸟们专用的工具?

我的意思是熟悉hibernate的人很少;很多人认为hibernate是体力活、民工活;有能力用好hibernate的又不开发了;本来就不怎么懂技术的搞管理去了。
反正见不到几个重视技术又懂技术的。
19 楼 ziyuan 2008-09-19  
ibatis完全符合lz的需求,,why not try it
18 楼 rockjava 2008-09-19  
fuwang 写道
我要抛弃hibernate,决定用ibatis之类的东西了。
不是hibernate不好,而是hibernate太深了,我玩不转,我觉得我再用几年也精通不了。
要做一个让人放心的业务系统,需要对hibernate非常熟悉,把hibernate用好才能做出来。
看看周边的情况,基本都是菜鸟在用 hibernate,做了几年的菜鸟在教新手如何用hibernate。
老板、售前、实施、项目经理都在叫:不就是增删改查吗?要有多简单就有多简单!


hibernate就是个错误?是菜鸟们专用的工具?

相关推荐

Global site tag (gtag.js) - Google Analytics