`

动态SQL的实现方式

阅读更多

在做企业级应用的时候会有很多的系统配置和 SQL语句需要编写。按照平常的做法是写在代码中,以接口或者 final static String的方式来定义变量,每次修改都要改动代码。好一点的做法是写到 properties或者有结构的 XML文档中。但是也是不能动态修改的,这里给大家介绍一种动态装载配置的做法。对于那种很多的查询条件的情况下尤其适用,只要给对应的参数就可以构造出对应的 SQL,采用 Hibernate QBC也可以达到该效果,二者配合使用相得益彰。

主类: ConfigCode

    /**

     * 获取相应的配置信息

     * @param signature 对象名

     * @return String

     */

    public String getCode (String signature);

    /**

     * 获取相应的动态配置信息

     * @param signature 对象名

     * @param map 对象方法

     * @return String 对象

     */

    public String getCode(String signature,Map parameterMap );

    /**

     * 利用配置文件来进行初始化工作

     * @param fileName 配置文件名字

     * @return 初始化是否成功

     */

  private boolean init(String fileName);

 

基本思路:

    将配置放到特定格式的 XML 文档中,在系统启动的时候加载进入内存。在需要修改的时候更改配置文件,不用重启服务器直接生效。其工作方式有两种,一种是 product 模式,系统不会检测文件的变更时间,如果有改动的话需要手动更新,这样提高了性能。还有 debug 模式,系统实时监控文档的变化,一旦文档发生变化即时重载该文件内容。使用前先实例化该类。

        ConfigCode sQlCode = ConfigCode.getInstance ( "classpath*:DAL.cfg.xml" );

        sQlCode.setDebug( true ); // 设置 debug 模式

 

XML 文档有个总配置文档 DAL.cfg.xml 来控制配置文档放在哪里。其格式如下:

<? xml version = "1.0" encoding = "UTF-8" ?>

< DataAccessLayer >

/**

  * <p> Code 主配置文件解析类 . </p>

  1 、每一行只有一对大括号 {}

  2 、在 { 之后紧跟!表示这个条件即使没有传值过来就采用默认值 "", 如果带有 || 则将 || 之前的作为默认值

  3 、如果 { 之后不跟 !, 表示如果不传值的话这个条件忽略

  4 、用 $$ 括起来的参数( key )将会用 parameterMap 中的 value 代替

  5 、采用 objectName.MethodName 作为 key 放在 parameterMap

  * @author Newway Jan 26, 2008 Email:gmhwq@126.com

  */   

< MappingFiles >

          < Mapping resource = "classpath*:sql/**/*.dal.xml" />

      </ MappingFiles >

</ DataAccessLayer >

 

支持通配符,意思是匹配 classpath sql 目录里面所有以 dal.xml 结尾的文件。 如果有多个配置文件可以写到总配置文档 DAL.cfg.xml 中。

 

好了,看看配置文件是怎么写的。配置是分为两层的,第一个前缀是指定某些功能模块,后面的是配置的名称,以防止名称的冲突。系统在启动过程中如果发现有冲突或在控制台做做出 WARNING

config.dal.xml

<? xml version = "1.0" encoding = "UTF-8" ?>

<!-- edited by Hewq (Bingo) -->

< DataAccessLayer >

      < BusinessObjects >

            < Object objectName = "config" >

            < Method name = "isDebug" > 1 </ Method >

            < Method name = "pageSize" > 10 </ Method >

            < Method name = "batchSize" > 1000 </ Method >

            < Method name = "MaxIndexJpg" > 7 </ Method >

            < Method name = "MaxFileSize" > 3145728 </ Method >

             <!-- contextPath ,if true path equals "/" -->

            < Method name = "ROOT" > false </ Method >

            < Method name = "DEFAULT_SHOP" > legenddesign </ Method >

            < Method name = "DOMAIN_NAME" > http://www.legendesign.net </ Method >    

            </ Object >

      </ BusinessObjects >

</ DataAccessLayer >

 

以上是配置项,还算简单吧。看看下面的动态 SQL

 

            < Method name = "getPaihang" ><![CDATA[

                  select hw from Hw hw ,Sort sort

                  where hw.sortId = sort.sortId

                  and sort.userName = ?

                  order by hw.hwBuys desc

            ]]></ Method >

           < Method name = "getShopDetail" ><![CDATA[

                  select new ShopDetail(s.userId,s.web,s.sitename,s.maddr,s.msn,s.mname,s.code,s.ymaddr,

                  s.ymname,s.storeName,s.visitTimes,s.modifyTime,

                  u.userMail,u.userTel,u.userPostcode,s.colorStyle,s.briefDesc)

                  from ShopDetail s,UserDetail u where s.userId =u.userId

                  and s.status = 1

                  and s.storeName = ?

            ]]></ Method >

            <!-- 登录历史统计 -->

            < Method name = "loginHistorySum" >

                  <![CDATA[

                        select user_Name,count(*) from t_Login_History

                        where 1=1

                              { and user_name = '$userName$'}

                              {? and      time >= $startTime$}

                              {? and      time <= $endTime$}

                          group by user_Name

                           order by count(*) desc

                  ]]>

            </ Method >

 

此处只是列出其中两个例子做说明,其余的看附件。有了这个动态的 SQL 之后就不用再代码中写那些烦人的 if else 的嵌套了。传递一个 map 进来自动匹配对对应的 SQL 出来,其原理是采用正则表达式来做的,具体业务不同的话可以改造实现。

例如 loginHistorySum ,如果传进来的 Map 为空则得出的 SQL 为:

       select user_Name,count(*) from t_Login_History where 1=1

      如果 Map 包含 userName ,则

      select user_Name,count(*) from t_Login_History where 1=1

        and user_name = 'userName'

      

//'userName' 将会用实际值代替,如果前面有问号 ? 的则用问号 ? 代替。

还有一条规则:之后紧跟!表示这个条件即使没有传值过来就采用默认值 "", 如果带有 || 则将 || 之前的作为默认值。

 

看看 Client 调用的例子:

            String sql = ConfigCode .getInstance ().getCode( "biz.loginHistorySum" , map);

            String countSql = ConfigCode .getInstance ().getCode( "biz.loginHistoryCount" , map);

 

 

如果你修改了 XML 文件不知道是否做了更改,也可以通过界面来观看改值的变化,也可以通过界面来刷新 XML 配置的缓存。


 

看看上面的配置项,是从 http://www.legendesign.net/system/sql/sqlCode.jsp 拷贝而来的。但是由于改页面需要系统权限才能看到。这些还算是比较机密的信息吧,权限又是另外一个大话题了。如果有什么疑问可以加入我们的 QQ 96642931 讨论, gmhwq@126.com Newway 。代码见附件。

 

 

  • 大小: 138.4 KB
分享到:
评论
16 楼 onecan 2010-05-08  
这个只是一个读写XML加上平常所使用的一些常用的功能的例子,并不能跟Ibatis相提并论,甚至还不能称为一个轮子吧,只是一些常用的东西用来整理一下方便自己开发。
15 楼 caoyangx 2010-04-16  
这就是轮子,实现一个iBATIS应有的功能,唯一不同的是iBATIS经过无数公司的项目考验,已经成为优秀的数据操作层框架。
自己写一个这样的东西费时费力,而且员工也不愿意去学习一个被圈在公司内部范围的技术,一旦离职就没有用武之地了。
14 楼 fanfq 2010-04-15  
晚上回家,好好的研究了一下,很终于调试出来的,感觉很不错,我没有用过ibatis。也不知道那个东西可以有类似的解决方案。

学习了,
感谢分享。。
13 楼 onecan 2010-04-15  
onecan 写道
     为什么不用Ibatis不是由我决定的,这个要看原来的项目是用什么技术来做的,而不是另外搞一套, 呵呵。当年用hibernate和ibatis做对比之后还是选择了hibernate,持久层也用过JPA/JDBC/EJB entity bean等,用了JPA和Hibernate之后写SQL的时候少了,但是复杂的业务还是的要用SQL比较好表达。ibatis只是研究过一下,没有深入应用。所以不好做评价 。
    这个动态SQL是仿造ibatis来做的,以前的公司用的框架就是山寨版的ibatis,这个XML定义是其中关键的一部分,拿到SQL之后还是要交给jdbc框架去执行。另外还可以做一些配置项的动态配置,提供一个界面查看和更新缓存。 根据项目需要来做对应的功能,自己来控制会灵活一些,我想这些功能大家也许能用的上,于是拿出来给大家分享一下,也许能提出更好的思路。
       最后说一下那个LegendShop就是用hibernate来实现的,并且用上了二级缓存。在没有很多的统计,表关联的情况下用hibernate还是开发速度上是很有优势的,基本的CURD可以规范化,尤其有了代码生成工具之后,对一个表的CURD代码可以用工具生成,然后再上面修改,对简单应用来讲开发速度提高了一大截。

在代码中缺少的类已经补上
12 楼 onecan 2010-04-15  
     为什么不用Ibatis不是由我决定的,这个要看原来的项目是用什么技术来做的,而不是另外搞一套, 呵呵。当年用hibernate和ibatis做对比之后还是选择了hibernate,持久层也用过JPA/JDBC/EJB entity bean等,用了JPA和Hibernate之后写SQL的时候少了,但是复杂的业务还是的要用SQL比较好表达。ibatis只是研究过一下,没有深入应用。所以不好做评价 。
    这个动态SQL是仿造ibatis来做的,以前的公司用的框架就是山寨版的ibatis,这个XML定义是其中关键的一部分,拿到SQL之后还是要交给jdbc框架去执行。另外还可以做一些配置项的动态配置,提供一个界面查看和更新缓存。 根据项目需要来做对应的功能,自己来控制会灵活一些,我想这些功能大家也许能用的上,于是拿出来给大家分享一下,也许能提出更好的思路。
       最后说一下那个LegendShop就是用hibernate来实现的,并且用上了二级缓存。在没有很多的统计,表关联的情况下用hibernate还是开发速度上是很有优势的,基本的CURD可以规范化,尤其有了代码生成工具之后,对一个表的CURD代码可以用工具生成,然后再上面修改,对简单应用来讲开发速度提高了一大截。
11 楼 whaosoft 2010-04-15  
lz 写的不错 呵呵
10 楼 dean_liu 2010-04-15  
想当年,我也做了类似的事情,不过后来知道了iBatis,发觉它就是我要的东西。
9 楼 zhongxuchen 2010-04-15  
请参看,当然我们现在用的已经更加简单了
http://zhongxuchen.iteye.com/admin/blogs/334013
用法一:
<!-- 配置辅助sql处理工具用于sql查询条件的处理 -->
<bean id="sqlToyContext" name="sqlToyContext" class="org.sagacity.sqltoy.SqlToyContext">
<property name="sqlcfgPlugin">
<bean id="sqlcfgPlugin" name="sqlcfgPlugin"
class="org.sagacity.sqltoy.plugin.impl.SqlConfigBaseXML">
<property name="cache">
<bean class="org.sagacity.sqltoy.cache.impl.HashSqlCache" />
</property>
<property name="debug" value="true" />
<property name="dialect" value="oracle" />
<property name="enableInStrategy" value="false" />
<property name="resourcesDir" value="classpath:/com/ccb/" />
</bean>
</property>
</bean>

用法二:

<!-- 配置辅助sql处理工具用于sql查询条件的处理,基于hibernate hbm.xml配置文件 -->
<bean id="sqlToyContext" name="sqlToyContext" class="org.sagacity.sqltoy.SqlToyContext">
<property name="sqlcfgPlugin">
<bean id="sqlcfgPlugin" name="sqlcfgPlugin"
class="org.sagacity.sqltoy.plugin.impl.SqlConfigBaseHibernate" />
</property>
</bean>
8 楼 kaki 2010-04-15  
山寨 ibatis? 不太像啊!
7 楼 lastForward 2010-04-15  
山寨 ibatis?
6 楼 andey007518 2010-04-15  
恩,XML集中进行管理,有效提高了程式的灵活性,学习中。。。 UP
5 楼 troyconder 2010-04-15  
楼主为什么不用ibatis?
4 楼 passtheball 2010-04-15  
把程序中组装sql的过程放到了xml中集中管理,和ibatis很像
3 楼 android9i 2010-04-15  
lz能说明下和iBatis相比的优势么

之前看的 还木有ib好用
2 楼 chbest 2010-04-15  
ibtias 就能全部做到.
特别是用了abator之后
1 楼 魔力猫咪 2010-04-15  
看起来和我当初做的仓库猫有点像哦。

相关推荐

    mybatis动态sqlmybatis动态sqlmybatis动态sql

    其中,动态SQL是MyBatis的一个重要特性,它允许用户根据不同的条件拼接SQL语句,从而实现更加灵活和可扩展的数据库操作。 在MyBatis中,动态SQL使用的主要方式是通过使用XML或注解来编写SQL语句。下面我将简单介绍...

    MyBatis注解配置映射器:动态SQL的实现

    java工程,练习通过MyBatis注解的方式配置SQL映射器,实现动态SQL.

    mybatis 样例,包含xml和annotation方式、关联映射、动态SQL等内容.zip

    在Mabits中,动态SQL通常是通过使用一组特殊的标签和代码块来实现的,这些标签和代码块可以根据条件包含或排除不同的部分,从而生成不同的SQL语句。动态SQL可以让开发者构建更灵活、高效的数据库操作语句,因为他们...

    分享一下SQL Server执行动态SQL的正确方式

    SQL Server执行动态SQL的话,应该如何实现呢?下面就为您介绍SQL Server执行动态SQL两种正确方式,希望可以让您对SQL Server执行动态SQL有更深的了解 动态SQL:code that is executed dynamically.它一般是根据用户输入...

    java配合MyBatis 多条件查询及动态SQL

    mysql 搜索 会员中心 消息 历史 创作中心 ...因为采用的是Mapper代理方式开发,我们可以通过xml来实现我们的sql语句,动态SQL再这里体现的淋漓尽致,下面我们看一下我们平常用到的xml配置,如下所示:

    Mybatis-04 动态SQL

    : 实现根据传入参数所携带的字段动态调整查询方式 2. where标签查询时如果某些条件没带可能导致SQL拼装有问题,比如多出一个and 3. Trim标签 4. choose标签:分支选择,只会进入其中一个 5. set标签:封装修改条件 6...

    Spring Boot整合mybatis使用注解实现动态Sql、参数传递等常用操作(实现方法)

    主要介绍了Spring Boot整合mybatis使用注解实现动态Sql、参数传递等常用操作(实现方法),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

    动态组合SQL语句方式实现批量更新的实例

    动态组合SQL语句方式实现批量更新的实例,需要的朋友可以参考一下

    经典SQL脚本大全

    │ │ 8.2.6 复制指定节点及其所有子节点到指定结点的处理示例(借鉴方式排序法).sql │ │ 8.2.6 复制指定节点及其所有子节点到指定结点的处理示例.sql │ │ 8.2.7 实现删除指定结点及所有子节点的处理触发器.sql ...

    ADO SQL服务器列表 SQL数据库列表 执行SQL脚本

    实现的功能包含。 1,禁用USB移动存储器,但是可以使用USB接口的非存储设备。主要是通过读取注册表操作。 2,可以注册DLL,OCX等动态链接库。不是使用regsvr32方式。 3,通过ADO方式列举SQL...

    MFC工程动态调用SQL数据库

    本工程为MFC工程,实现动态调用sql数据库里的任意一张表: 一、实现四种查询方式及遍历一张表格,并数据传输 二、实现插入、删除、修改表格数据 三、以上功能都封装好了,用户只需调用即可 与数据库的接口都在...

    Mybatis中的动态SQL语句解析

     Mybatis常用xml配置的方式,使用xml的几个简单的元素,便能完成动态SQL的功能,大量的判断都可以在mybaties的映射xml里面配置,以达到许多需要大量代码才能实现的功能,大大减少了代码量,体现了Mybatis的灵活、

    在Sql Server 数据库中利用存储过程实现动态交叉表

    详细介绍了SQL server数据库在存储过程中实现动态交叉表的实现方式和作用。

    SQL Server 2008数据库设计与实现

     5.2.5 决定域的实现方式  5.2.6 设置模式  5.2.7 评审“最终的”实现模型  5.3 实现设计  5.3.1 创建基本表结构  5.3.2 添加唯一性约束  5.3.3 构建默认约束  5.3.4 添加关系(外键)  5.3.5 ...

    Sqlserver2000经典脚本

    │ 8.2.5 校验表中数据是否有循环编码的通用存储过程.sql │ │ 8.2.6 复制指定节点及其所有子节点到指定结点的处理示例(借鉴方式排序法).sql │ │ 8.2.6 复制指定节点及其所有子节点到指定结点的处理示例...

    c# 反射获取传入对象的属性拼接sql语句实现增、删、改、查

    利用反射动态拼接sql。 daohelper属于DAL层,objectdata类属于BLL层,BLL层引用DAL层。映射数据的表继承objectdata类。例如,数据表book,根据字段与属性一一对应的方式创建book类,插入数据库时,直接book.save()

    Java封装SqlServer

    用Java简单的实现SqlServer的封装,麻雀虽小,五脏俱全,用类的方式封装使得解读Java数据库操作更为明确,其中包含了查询、执行sql等。

    .NET Core中的一个接口多种实现的依赖注入与动态选择看这篇就够了

    最近有个需求就是一个抽象仓储层接口方法需要SqlServer以及Oracle两种实现方式,为了灵活我在依赖注入的时候把这两种实现都给注入进了依赖注入容器中,但是在服务调用的时候总是获取到最后注入的那个方法的实现,这...

    动态游标实现数据内容分列显示

    以动态游标的方式实现让数据库的内容分列显示,达到想要的显示效果

Global site tag (gtag.js) - Google Analytics