论坛首页 入门技术论坛

开创性的陈氏数据库动态查询设计

浏览 11904 次
该帖已经被评为新手帖
作者 正文
   发表时间:2009-02-17   最后修改:2009-04-22

(新版增加了直接结果映射VO的功能无需再写rowcallbackhandler了,集成ehcache、memcached提高处理效率)

犹豫了很久,还是决定将自己的东西(sagacity睿智开发框架)的一部分逐步奉献给大家,首先申明一下版权问题,请注明“陈氏查询”!

     进入正题:

     首先介绍一下sagacity(睿智)框架:其包括快速原型的页面框架(这里面也有一个非常独到人性化的界面的设计),sagacity-core核心代码库提供针对企业应用开发所需要的工具类和组件,sagacity-toolkit 工具库,包括快速原型项目生成,excel导入工具(用于项目试运行阶段数据初始化);sagacity-struts:基于struts2+spring+hibernate+sitemesh+spring security技术以实际企业开发项目为背景非常实用演示项目。sagacity项目从实际项目出发,贯穿整个项目周期提供优雅的实现以及从开发人员的角度着眼简化开发难度!这里不一一而谈。

     第一讲:陈氏查询

     先抛一个问题:大家平时做数据库查询时查询条件很多也不定时怎么写hql以及sql语句?

     比如:

     queryStr.append("select *  ");
     queryStr.append("from OA_CAR_REGIST t ");
     queryStr.append("where 1=1 ");

     if(CarRegiestVO.isActive!=null)
          queryStr.append(" and t.IS_ACTIVE is ? ");

     if(CarRegiestVO.beginDate!=null && CarRegiestVO.endDate!=null)
          queryStr.append("   and t.REGIST_DATE>=? and t.REGIST_DATE<= ? ");

     if(CarRegiestVO.carMode!=null)
          queryStr.append("      and t.CAR_MODE like  "+carMode+"%");
     sql结构非常混乱,从数据库客户端写好的sql语句还得用stringBuffer给拼接起来,以后要是改写一下语句还得debug程序得到最后的语句,太累了!

     我们的做法:

     我们的项目基于hibernate的,如下基于hibernate NamedQuery扩展。

     <hibernate-mapping>
 <sql-query name="hr_searchOrganInfo">
  <![CDATA[
  from HrOrganInfo
  where 1=1
  #[and createDate>=? and createDate<=?]
  #[and ORGAN_NO like ?]
  #[and ORGAN_NAME like ?]
  #[and IS_ACTIVE=?]
 ]]>
 </sql-query>
 
 <sql-query name="hr_loadOrganTree">
 <![CDATA[
  select  b.ORGAN_NO,b.ORGAN_NAME,b.PRE_ORGAN_NO,0 AS TYPE
  from HR_ORGAN_INFO b
  where 1=1
  #[and b.ORGAN_NO=?]
  #[and b.IS_ACTIVE=?]
  union
  select b.ORGAN_NO,b.ORGAN_NAME,b.PRE_ORGAN_NO,0 AS TYPE
  from HR_ORGAN_INFO a,HR_ORGAN_INFO b
  where 1=1
  #[and a.ORGAN_NO=b.PRE_ORGAN_NO and (a.ORGAN_NO=? or b.PRE_ORGAN_NO=a.ORGAN_NO)]
  #[and b.IS_ACTIVE=?]
 ]]>
 </sql-query>
  对于不定的查询条件以#[和]标记对,支持嵌套

我们的调用过程:

 /**
  * 分页方式查询机构信息
  * @param organInfoVO
  * @param pageModel
  * @return
  * @throws Exception
  */
 public PaginationModel searchOrganInfo(OrganInfoVO organInfoVO,
   PaginationModel pageModel) throws Exception {
  return this.findPageByhql("hr_searchOrganInfo", null, new Object[] {
    organInfoVO.getBeginDate(),
    organInfoVO.getEndDate(),
    organInfoVO.getOrganNo(),
    organInfoVO.getOrganName(),
    organInfoVO.getIsActive() },
    pageModel);
 }

    

在我们BaseDAOSupport中提供findPageByHql以及其它大量针对数据库查询的方法,在方法调用时只需要将参数完整化的以对象数组(或List),对于如状态选择:-1表示全部等特性,以及blank值的处理,我们提供了convertSqlParams(objects),convertSqlParams(obj,new Object[-1,""]),判断对象为空或-1则转为

null,用法:

 return this.findPageByhql("hr_searchOrganInfo", null, new Object[] {
    organInfoVO.getBeginDate(),
    organInfoVO.getEndDate(),
    organInfoVO.getOrganNo(),
    organInfoVO.getOrganName(),
    convertSqlParams(organInfoVO.getIsActive() ,-1)},
    pageModel);
 }

当然也可以批量转(转""为null)

return this.findPageByhql("hr_searchOrganInfo", null, convertSqlParams(new Object[] {
    organInfoVO.getBeginDate(),
    organInfoVO.getEndDate(),
    organInfoVO.getOrganNo(),
    organInfoVO.getOrganName(),
    organInfoVO.getIsActive() }),
    pageModel);
 }

 

实现原理很简单(个人觉得这只是一个idea不属于技术范畴,说穿了谁都能实现只是实现的代码简繁而已),判断#[]中的问号所对应的参数是否为null(当然考虑like 和is,like将值直接替换进去,is 判断数据类型是否为null以及boolea类型,不是则将#[]内容切除),为null将#[]内容切除,是则将#[和]标记用""替换掉,这样整体

代码实现起来优雅简单,sql语句的可读性和可维护性大大增强!

当然你会找出一个极其变态难处理的sql整合(目前我们项目中还没有遇到),我们这个东西怎么做呢?其实

findPageByhql("hr_searchOrganInfo",param..param),第一个参数既可是是NamedQuery也可以是sql(hql)语句,自己组合咯,特殊问题特殊对待。

sagacity的宗旨在于不强迫你改变你的习惯,考虑特殊情况,为开发提供方便!

sagacity代码这几天整理一下,重新划分一下,将标签部分独立出来,减少耦合性将尽快对大家提供后台开发所需要的代码!

期待第二讲吧!

谢谢支持!

另外对于参数位置不容易记问题,其实我们这边是提供了

/**
  * @todo 分页查询
  * @param hql
  * @param paramNames
  *            :参数名称
  * @param params
  *            :参数值
  * @param paginationModel
  *            :分页模型,含页号
  * @return
  */
 protected PaginationModel findPageByhql(final String hqlOrNamedQuery,
   final String[] paramNamed, final Object[] paramsValue,
   final PaginationModel paginationModel) {

}

paramNamed 参数方式的。

哈哈,说一下ibatis,ibatis确实能够实现类似的功能,但个人觉得没有这个灵活和优雅,下面发一张图,ibatis多条件动态查询无法让sql看起来如此优雅整洁:



 

再对比一下ibatis的做法:

<statement id="someName" resultMap="account-result" >
select * from ACCOUNT
<dynamic prepend="where">
<isGreaterThan prepend="and" property="id" compareValue="0">
ACC_ID = #id#
</isGreaterThan>
<isNotNull prepend=”and" property="lastName">
ACC_LAST_NAME = #lastName#
</isNotNull>
</dynamic>
order by ACC_LAST_NAME
</statement>

 

效果一目了然了,代码多,还破坏了sql的整体性

    

  • 大小: 12.2 KB
   发表时间:2009-02-17  
有一个简单问题复复杂化的例子:

hibernate的一般用法:

EO eo = new EO();
set get......

query....
0 请登录后投票
   发表时间:2009-02-17  
很好,实现类似于ibatis
0 请登录后投票
   发表时间:2009-02-17  
哈哈,简单的hibernate query查询当然不需要这么搞了,我们针对复杂多条件查询,简单的可以采用Criteria,我这里只强调这个方式,具体jdbc查询的反调对象这类的不着重说,
BaseDAOSupport中提供了实现:
protected List findByJdbcQuery(String sqlOrNamedSql,Object paramsObj,RowCallbackHandler rowCallHandler)
0 请登录后投票
   发表时间:2009-02-17  
没错,灵感来自ibatis
0 请登录后投票
   发表时间:2009-02-17  
其实这个东西并不局限于hibernate,我们项目中是提供了针对hibernate的集成,目的是提供针对多条件查询
0 请登录后投票
   发表时间:2009-02-17  
嗯,不错,很有面向对象的风格。
0 请登录后投票
   发表时间:2009-02-18  
kimmking 写道
有一个简单问题复复杂化的例子:

hibernate的一般用法:

EO eo = new EO();
set get......

query....


这个问题怎么会用这种方式解决呢?直接(EO)this.get(EO.class,id),没有仔细看文章才会有这样的结论,
敢拿出来露当然有一些独到的地方,简单东西其实大家做法都差不多,属于没有必要谈的事情!
0 请登录后投票
   发表时间:2009-02-19  
还行,思路挺好,不过啥叫“陈氏查询”
0 请登录后投票
   发表时间:2009-02-19  
我比侧向与用ibatis
0 请登录后投票
论坛首页 入门技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics