zoukankan      html  css  js  c++  java
  • (转)mybatis:动态SQL

    概述:在mybatis中,动态语句是个非常强大和灵活的功能,并且动态语句可以放在sql的任何地方,利用该功能,我们可以写出非常灵活的代码。在mybatis的动态语句中常常可能会用到以下几个运算和逻辑判断符:

    1,"!=" : 表示不等于

    2,"=":表示等于。注意是一个等号。

    3,"and" : 逻辑与(小写)

    4,"or" : 逻辑或(小写)

    1 if元素

        该元素是我们经常会用到的,常用语判断传入的某个参数是否为null或者为某个指定的值,例如下面的语句。

    <select id=”selectUsers” parameterType=”int” resultType=”User”>
        select
           user_id as "id",
           user_name as "userName",
           hashed_password as "hashedPassword"
        from some_table
        <if test="id != null and id!=''">
               where id = #{id}
        </if>
       </select>

    该语句的意思是判断参数id是否不为null以及不为空字符串,如果是则查询指定id的记录,不然查询全部的记录。元素里面的test属性,顾名思义就是测试的意思,即测试指定的表达式是否成立。

     ps:test后面指定的参数为传入的参数

    2 choose、when和otherwise

        这3个元素是组合起用的,表达一种 if..else..的意义。例如:

    <select id=”selectUsers” parameterType=”int” resultType=”User”>
        select
           user_id as "id",
           user_name as "userName",
           hashed_password as "hashedPassword"
        from some_table
        <choose>
          <when test="id != null">
                 where id = #{id}
          </when>
          <otherwise>
                 where id = '123'
          </otherwise>
       </select>

     上面表达的意思是,如果参数id不为空,则查询指定id的记录,否则查询id为123的记录。

    这里只列举了一个when,其实可以连续的添加多个,但是otherwise只能有一个。

    3 trim、where、set

        这3个元素主要功能就是帮助我们去除多余的关键字。where对应sql语句中的where关键字,set对应更新语句中的set关键字。下面列举一个例子,如下:

    <select id="findActiveBlogLike"
      parameterType="Blog" resultType="Blog">
             SELECT * FROM BLOG
               WHERE
             <if test="state != null">
                  state = #{state}
            </if>
            <if test="title != null">
                  AND title like #{title}
            </if>
            <if test="author != null and author.name != null">
                   AND title like #{author.name}
             </if>
    </select>  

    如果第1个if和第2个if条件成立,则形成的SQL为:

    SELECT * FROM BLOG WHERE state=#{state} AND title like #{title}

    如果第2个if和第3个if条件成立,则形成的SQL为:

    SELECT * FROM BLOG WHERE  AND title like #{title} AND title like #{author.name} 

    明显第二条语句是错误的。如果让我们自己来考虑到各种可能,那么在面对复杂的动态语句的时候,将会是非常头痛的事情,为此,mybatis框架为我们提供了更好的解决办法,例句如下:

    3.1 trim元素

        该元素的目的就是却掉前后执行的内容,其表达式如下:

    <trim prefix="" prefixOverrides="" suffix="" suffixOverrides="" ></trim>

    prefixOverrides:表示在trim包含的sql语句中,要被覆写的前缀,可以用"|"或者"||"来分割,例如:

      <trim  prefixOverrides="and | or" ></trim> 
                这里面的and和or不区分大小写。

    prefix与prefixOverrides搭配使用,它们俩总是同时出现。该属性表示由prefixOverrides指定的前缀要被覆写成的内容。例如:

    <trim prefix="" prefixOverrides="and | or" ></trim>   //表示把第一个and或者or变为空
    <trim prefix="where" prefixOverrides="and " ></trim>  //表示把第一个and变为where

    suffixOverridessuffix和上面两个的规则是一样的,只是这两个是处理语句的最后,而上面两个是处理语句的最前。

        把上面的例子改为下面的方式:

    <select id="findActiveBlogLike"
      parameterType="Blog" resultType="Blog">
             SELECT * FROM BLOG
        <trim prefix="where" prefixOverrides="and | or">        
             <if test="state != null">
                  state = #{state}
            </if>
            <if test="title != null">
                  AND title like #{title}
            </if>
            <if test="author != null and author.name != null">
                   AND title like #{author.name}
             </if>
    </select>  

    如果条件1和条件2成立,则形成的SQL为:

    SELECT * FROM BLOG where state = #{state} AND title like #{title}

    可以发现,虽然state前面没有and或者or,但是trim会为语句加上where。

    如果条件2和条件3成立,则形成的SQL为:

    SELECT * FROM BLOG WHERE title like #{title} AND title like #{author.name}

    这时,会把trim元素中的SQL语句的前缀AND变为where。

    上面的效果和下面是一样的:

    <select id="findActiveBlogLike"
      parameterType="Blog" resultType="Blog">
             SELECT * FROM BLOG WHERE
        <trim prefix="" prefixOverrides="and | or">        
             <if test="state != null">
                  state = #{state}
            </if>
            <if test="title != null">
                  AND title like #{title}
            </if>
            <if test="author != null and author.name != null">
                   AND title like #{author.name}
             </if>
    </select>  

    我们再加上对suffix的使用,如下:

    <select id="findActiveBlogLike"
      parameterType="Blog" resultType="Blog">
             SELECT * FROM BLOG
        <trim prefix="where" prefixOverrides="and | or"  suffix="" suffixOverrides=",">        
             <if test="state != null">
                  state = #{state}
            </if>
            <if test="title != null">
                  AND title like #{title}
            </if>
            <if test="author != null and author.name != null">
                   AND title like #{author.name} ,
             </if>
    </select>  

    这时,如果条件3成立,会除掉最后的逗号","。

    trim元素非常灵活,可以中在任何的位置,但由于我们在实际的使用中,where语句的后面和set语句的后面是最容易要处理的,所以mybatis又特意为我们定义了where元素和set元素。

    3.2 where元素

        先举例如下:

    <select id=”findActiveBlogLike”
         parameterType=”Blog” resultType=”Blog”>
     SELECT * FROM BLOG
     <where>
         <if test=”state != null”>
              state = #{state}
         </if>
         <if test=”title != null”>
              AND title like #{title}
         </if>
         <if test=”author != null and author.name != null”>
              AND title like #{author.name}
         </if>
    </where>

     如果第2个if才成立,那么where元素会去掉AND。

    3.3 set元素

        set元素会动态前置SET关键字,而且也会消除任意无关的逗号。

    <update id="updateAuthorIfNecessary"
     parameterType="domain.blog.Author">
     update Author
     <set>
          <if test="username != null">username=#{username},</if>
          <if test="password != null">password=#{password},</if>
          <if test="email != null">email=#{email},</if>
          <if test="bio != null">bio=#{bio},</if>
     </set>
     where id=#{id}
    </update>

    4 foreach

        foreach元素是非常强大的,它允许你指定一个集合,声明集合项和索引变量,它们可以用在元素体内。它也允许你指定开放和关闭的字符串,在迭代之间放置分隔符。这个元素是很智能的,它不会偶然地附加多余的分隔符。通常是构建在IN条件中的。比如:

    <select id="selectPostIn" resultType="domain.blog.Post">
        SELECT *
        FROM POST P
        WHERE ID in
            <foreach item="item" index="index" collection="list"
                                                open="(" separator="," close=")">
                      #{item}
              </foreach>
    </select>

    注意:你可以传递一个List实例或者数组作为参数对象传给MyBatis。当你这么做的时候,MyBatis会自动将它包装在一个Map中,用名称作为键。List实例将会以“list”作为键,而数组实例将会以“array”作为键。 

    1, item="item":这里指定的是集合遍历的时候每个元素的名字,就好比为集合中的对象定义了一个名字,我们可以通过该名字来使用对象,这里的例子取名为“item”,我们可以随意的改名。如果这个名字指定的是一个对象,那么我们也可以这么使用:#{item.name},即访问对象中的name属性。

    2,collection="list":如果我们传递的参数是个对象,然后是要遍历对象中的某个集合,那么我们可以这么使用:collection="param.list",即:传入的参数名为param,该对象里面有个名为list的集合属性。

    5 使用foreach进行批插入

    方法:

     insert into Author (username ,password ,email )  
        values 
        <foreach collection="list" item="item" index="index" separator="," > 
            (#{item.username},#{item.password},#{item.email }) 
        </foreach>

    6 insert语句中使用动态sql

    下面是一个在项目开发中使用的实际例子

    主要是对<sql id="InfoManageSet">中set标签的使用,其中包含直接插入的字段和需要判断的字段。主要通过判断来达到一条sql语句的复用!

        <!-- 将平台转发的实时贷记或借记业务入库-->
        <insert id="insertOneCreditOrDebit" parameterType="TransferParam" >
             insert  into trndetail <include refid="InfoManageSet" />
        </insert >
        
        <sql id="InfoManageSet">
             <set >
                     <!-- 支付业务头组件 -->
                     transtype = #{transtype},
                     subday = substr(#{subdate},7,2), 
                     <if test="transno != null and transno !=''">transno = #{transno},</if>
                     <if test="transno == null or transno ==''">transno = SEQ_CENTER_PAY_TRN.NEXTVAL,</if>
                     subnode = #{subnode},
                     curtype = #{curtype},
                     trnmoney = #{trnmoney},
                     transcode = #{transcode},
                     acttrnmoney =#{trnmoney}-#{feemoney},
                     feemoney = #{feemoney},
    
                     <!-- 付款方信息组件 -->
                     payaccbankno = #{payaccbankno},
                     payaccno = #{payaccno},
                     accttype = #{accttype},
                     <if test="payaccname != null and payaccname !=''">payaccname = #{payaccname},</if>
                     <if test="payaccaddr != null and payaccaddr !=''">payaccaddr = #{payaccaddr},</if>                
                     <!-- 收款方信息组件 -->
                     acpaccbankno = #{acpaccbankno},
                     acpaccno = #{acpaccno},
                     acpacctype =#{acpacctype},
                     acpaccname = #{acpaccname},
                     acpaccaddr = #{acpaccaddr},
                     
                    <!-- 附言和回执附言 -->
                     <if test="atcmemo != null and atcmemo !=''">atcmemo = #{atcmemo},</if>
                     <if test="retatcmemo != null and retatcmemo !=''">retatcmemo = #{retatcmemo},</if>
    
                     <!-- 针对104 业务报文要素进行相关处理-->
                     <if test="transtype =='104'">               
                     tranchannel = #{tranchannel},
                     paybankno = #{paybankno},
                     acpbankno = #{acpbankno},
                     sndnode = #{payaccbankno},
                     rcvnode = #{acpaccbankno},
                     <!-- 轧差信息组件 -->
                     <if test="setwrkdate != null and setwrkdate !=''">setwrkdate = #{setwrkdate},</if>
                     <if test="netno != null and netno !=''">netno = #{netno},</if>
                     <!-- 对账处理信息组件 -->
                     <if test="chkdate != null and chkdate !=''">chkdate = #{chkdate},</if>
                    <if test="chknetno != null and chknetno !=''">chknetno = #{chknetno},</if>
                     </if>
                     
                     <!-- 针对105 业务报文要素进行相关处理-->
                     <if test="transtype =='105'">
                     tranchannel = #{tranchannel},
                     paybankno = #{paybankno},
                     acpbankno = #{acpbankno},
                     sndnode = #{acpaccbankno},
                     rcvnode = #{payaccbankno},
                     purtypecode = #{purtypecode},
                     applytypecode = #{applytypecode},
                     purnote = #{purnote},
                     token = #{token}
                     </if>
    
                     <!-- 默认字段 -->
                     wrkdate = #{wrkdate},
                     sysdtime = sysdate,
                     subdate = #{subdate},
                     pstatus = #{pstatus},
                     pdtime = #{pdtime},
    
                     srflag = #{srflag},
                     orderno = concat(#{subdate}, SEQ_CENTER_PAY_TRN.NEXTVAL),
                     returnedmoney = '0', 
                     returnedfeemoney = '0', 
                     orgchlcode = '01', 
                     destchlcode = '01',
                     setflag = '0',
                     settype = '0', 
                     interestflag = '0', 
                     cancelflag = '0', 
                     returnnum = '0', 
                     trnreverseflag = '0', 
                     trnbackflag = '0', 
                     dbtrfundflag = '0', 
                     plyfundflag = '0',
                     <if test="retcode != null and retcode !=''">retcode = #{retcode},</if>
                    <if test="retdesc != null and retdesc !=''">retdesc = #{retdesc},</if>
                    <if test="newtransno != null and newtransno !=''">transno = #{newtransno},</if>            
              </set>
        </sql >
  • 相关阅读:
    通用权限管理设计 之 数据库结构设计
    jQuery LigerUI 插件介绍及使用之ligerDateEditor
    jQuery LigerUI 插件介绍及使用之ligerTree
    jQuery LigerUI V1.01(包括API和全部源码) 发布
    jQuery liger ui ligerGrid 打造通用的分页排序查询表格(提供下载)
    jQuery LigerUI V1.1.5 (包括API和全部源码) 发布
    jQuery LigerUI 使用教程表格篇(1)
    jQuery LigerUI V1.0(包括API和全部源码) 发布
    jQuery LigerUI V1.1.0 (包括API和全部源码) 发布
    nginx keepalived
  • 原文地址:https://www.cnblogs.com/lixuwu/p/5915547.html
Copyright © 2011-2022 走看看