`

动态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  
看起来和我当初做的仓库猫有点像哦。

相关推荐

    用pb编写动态sql类型

    虽然没有明确的文件类型信息,但我们可以假设这可能是一些源代码文件(如.PBL库文件,.PBD工程文件,或者.PY、.TXT等文本文件),或者是包含了关于第三种动态SQL实现方式的文档。这些文件可能详细阐述了一种特定的...

    hibernate实现动态SQL查询

    在实际开发中,应根据项目需求合理选择实现动态SQL的方式,以提高代码的可读性和可维护性。 在Spring MVC环境中,整合Hibernate和FREEMARKER,可以构建出高效、灵活的数据访问层,为Web应用提供强大的数据查询能力...

    4-动态SQL语句编写.pdf

    这是一种常用的动态SQL实现方式,可以避免在拼接SQL语句时产生不合法的SQL。 #### 2. trim标签 trim标签用于处理SQL语句中的多余字符,比如在where条件后自动添加"and"或"or"关键字,或者在set语句中自动去除末尾...

    Mybatis实现动态代理,动态SQL

    "Mybatis实现动态代理,动态SQL" Mybatis框架可以通过配置的形式为DAO接口生成动态代理实现类,从而...Mybatis框架提供了多种方式来实现动态代理和动态SQL,可以根据不同的需求选择合适的方法来实现动态代理和动态SQL。

    SQLServer动态SQL语句的用法

    SQL Server 中的动态 SQL 语句是一种灵活的查询方式,它可以根据不同的情况生成不同的 SQL 语句。动态 SQL 语句可以用来实现复杂的业务逻辑,提高查询效率和灵活性。 普通 SQL 语句和动态 SQL 语句的区别 普通 SQL...

    《kettle中实现动态SQL查询》博客文章示例代码

    本文将深入探讨如何在Kettle中实现动态SQL查询,这对于处理复杂的数据库操作和数据迁移至关重要。我们将讨论问号占位符和命名参数这两种方法,并分析它们的区别。 首先,让我们理解什么是动态SQL查询。在传统的SQL...

    ibatis动态SQL标签用法

    iBatis动态SQL标签用法 iBatis是Java持久层框架,提供了...iBatis的动态SQL标签提供了一种灵活的方式来生成动态的SQL语句。通过使用动态SQL片段和动态条件分页查询,我们可以提高代码的可重用性、查询效率和灵活性。

    动态SQL 并且把返回的值赋给变量

    它提供了一种安全的方式来自定义和执行动态SQL,同时还可以绑定参数,避免了SQL注入的问题。 #### `sp_executesql`的基本语法 `sp_executesql`的基本语法如下: ```sql sp_executesql @stmt = N'&lt;your SQL ...

    动态SQL与绑定变量

    - 执行DDL(Data Definition Language)语句,如创建表、视图等,这些语句无法通过静态SQL实现。 ### 2. 为什么使用动态SQL 虽然静态SQL具有编译时检查、更好的性能优化等优点,但其灵活性有限,无法应对所有编程...

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

    在本项目中,我们将深入探讨如何使用MyBatis的注解配置来实现SQL映射器,进而掌握动态SQL的使用。 首先,让我们理解MyBatis中的注解配置。在MyBatis中,我们可以使用注解在接口方法上直接定义SQL语句,这种方式简洁...

    mybatis之动态SQL

    动态 SQL 在 MyBatis 中主要通过 XML 映射文件或者注解来实现。在 XML 映射文件中,我们可以使用 `&lt;if&gt;`, `&lt;choose&gt;`, `&lt;when&gt;`, `&lt;otherwise&gt;`, `&lt;where&gt;`, `&lt;foreach&gt;` 等标签来构建动态 SQL。这些标签可以让我们...

    SpringBoot+JPA+Freemarker 生成动态SQL

    通过这种方式,SpringBoot+JPA+Freemarker能够帮助我们构建一个强大的动态SQL生成系统,它允许我们在不硬编码SQL的情况下,根据业务需求灵活地构建复杂的查询。这种方式提高了代码的可读性和可维护性,减少了因SQL...

    本地动态SQL的开发

    为了保持代码的可读性和易于维护性,应该尽可能简化动态SQL语句,并在适当的文档中清晰地描述其实现逻辑。 通过上述介绍,可以看出动态SQL是一种非常有用的工具,尤其是在需要高度灵活性的情况下。然而,正确地使用...

    sql语句、动态SQL语句基本语法

    - 在大多数数据库系统中,动态SQL可以通过字符串拼接和EXECUTE命令实现。例如,在PL/SQL(Oracle)中,可以写成: ```sql DECLARE sql_query VARCHAR2(200); BEGIN sql_query := 'SELECT * FROM table_name ...

    动态SQL语句

    2. **使用EXECUTE()函数**:虽然它可以实现动态SQL的执行,但在安全性和性能上不如Sp_Executesql。当动态SQL语句包含变量时,使用EXECUTE()需要特别小心SQL注入问题。 ```sql DECLARE @sql NVARCHAR(MAX); SET @...

    Oracle中动态SQL详解

    #### 三、动态SQL的实现方式 在Oracle中,实现动态SQL主要通过`EXECUTE IMMEDIATE`命令来完成。此命令用于执行动态构建的SQL语句。具体语法如下: ```sql EXECUTE IMMEDIATE '动态SQL语句' USING [绑定变量] ...

    PowerBuilder中动态SQL的实现.pdf

    在张长伟所著的《PowerBuilder中动态SQL的实现.pdf》一文中,作者详细探讨了PowerBuilder中动态SQL的不同实现方式及其使用场景。 首先,文章介绍了PowerBuilder中嵌入式SQL语句和动态SQL语句之间的区别。嵌入式SQL...

    动态SQL四种类型的语句格式

    动态SQL的这四种格式各有其特点和适用场景,开发者可以根据实际需求选择最适合的方式来实现动态SQL操作。需要注意的是,虽然动态SQL提供了便利,但也可能带来SQL注入等安全问题,因此在编写时需确保输入的安全性,并...

    MyBatis动态拼接SQL

    MyBatis通过`&lt;if&gt;`, `&lt;choose&gt;`, `&lt;when&gt;`, `&lt;otherwise&gt;`, `&lt;where&gt;`, `&lt;set&gt;`, `&lt;foreach&gt;`等标签来实现动态SQL的构建。 1. `&lt;if&gt;`标签:用于判断某个条件是否成立,如果成立则插入相应的SQL片段。例如,当查询...

Global site tag (gtag.js) - Google Analytics