动态SQL

一、动态SQL

1、if

if元素用于判断,一般用作是否应该包含某一个查询条件

<if test="boolean表达式"></if>

    <!--查询工资大于等于1000的员工-->

    <select id="query1" resultType="Employee">

        SELECT * FROM employee

        <if test="minSalary!=null">

            WHERE salary >= #{minSalary}

        </if>

    </select>

    <!--查询工资在1000-2000之间的员工-->

    <select id="query2" resultType="Employee">

        SELECT * FROM employee WHERE 1 = 1

        <if test="minSalary!=null">

            AND salary >= #{minSalary}

        </if>

        <if test="maxSalary!=null">

            AND salary <= #{maxSalary};

        </if>

    </select>

2、choose、when、otherwise

相当于switch

<!--查询指定部门的员工信息-->

  <select id="query3" resultType="Employee">

      SELECT * FROM employee WHERE 1 = 1

      <if test="minSalary!=null">

          AND salary >= #{minSalary}

      </if>

      <if test="maxSalary!=null">

          AND salary <= #{maxSalary}

      </if>

      <!--假如下拉列表获取的部门id,"所在部门"这个要排除,设为-1-->

      <!--<if test="deptId > 0">

          AND deptId = #{deptId}

      </if>-->

      <choose> <!--相当于switch判断-->

          <when test="deptId > 0">AND deptId = #{deptId}</when>

          <otherwise>AND deptId IS NOT NULL</otherwise>

      </choose>

  </select>

3、where

where元素: 判断查询条件是否有WHERE关键字,如果没有,则在第一个查询条件之前,插入一个WHERE,如果发现查询条件AND 或者 OR开头,也会把第一个查询条件前的AND/OR 替换成WHERE。

这种方式避免了 WHERE 1 = 1的形式

    <select id="query3" resultType="Employee">

        SELECT * FROM employee

        <where>

            <if test="minSalary!=null">

                AND salary >= #{minSalary}

            </if>

            <if test="maxSalary!=null">

                AND salary <= #{maxSalary}

            </if>

            <choose> <!--相当于switch判断-->

                <when test="deptId > 0">AND deptId = #{deptId}</when>

                <otherwise>AND deptId IS NOT NULL</otherwise>

            </choose>

        </where>

    </select>

4、set

set元素和where元素相似,也能根据set中的sql动态的去掉最后的逗号,并在前面添加set关键字,如过没有内容,也会选择忽略set语句。

应用场景:

need-to-insert-img

因为password没有设置值,所以就要采用if来动态判断password是否为空,如果为空,则不拼接,但是此时会出现问题,上面拼接的语句最后会存在一个 “,” 。

need-to-insert-img

若不使用set:update employee name = #{name}, where id = #{id}

<update id="update">

        UPDATE employee

        <set>

            <if test="name!=null">

                name = #{name},

            </if>

            <if test="sn!=null">

                sn = #{sn},

            </if>

            <if test="salary!=null">

                salary = #{salary},

            </if>

        </set>

        WHERE id = #{id};

</update>

5、trim

trim是更强大的格式化SQL的标签

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

<!--trim包含的动态SQL-->

</trim>

前提如果trim元素包含内容返回一个字符串,则

prefix : 在这个字符串之前插入prefix属性值

prefixOverrides : 字符串内容以prefixOverrides中的内容开头(可以包含管道符号|),那么使用prefix属性值替换内容的开头

suffix : 在这个字符串之后插入suffix属性值

suffixOverrides : 字符串的内容以suffixOverrides中的内容结尾(可以包含管道符号|),那么使用suffix属性值替换内容的结尾

need-to-insert-img

使用where等价于:

<trim prefix="WHERE" prefixOverrides="AND |OR ">

</trim>

<select id="query3" resultType="Employee">

    SELECT * FROM employee

    <!--和使用where标签效果一样-->

    <trim prefix="WHERE" prefixOverrides="AND|OR">

        <if test="minSalary!=null">

            AND salary >= #{minSalary}

        </if>

        <if test="maxSalary!=null">

            AND salary &lt;= #{maxSalary}

        </if>

        <choose> <!--相当于switch判断-->

            <when test="deptId > 0">AND deptId = #{deptId}</when>

            <otherwise>AND deptId IS NOT NULL</otherwise>

        </choose>

    </trim>

</select>

注意:此时AND和OR后面有一个空格

使用set等价于:

<trim prefix="WHERE" suffix="" suffixOverrides=",">

</trim>

<trim prefix="SET" suffix="" suffixOverrides=",">

        <if test="name!=null">

            name = #{name},

        </if>

        <if test="sn!=null">

            sn = #{sn},

        </if>

        <if test="salary!=null">

            salary = #{salary},

        </if>

    </trim>

6、foreach

SQL中有时候使用IN关键字,如WHERE id IN(10,20,30),此时可以使用${ids}直接拼接SQL ,但是会导致SQL注入问题,要避免SQL注入,只能使用#{}方式,此时就可以配合使用foreach元素了。foreach元素用于迭代一个集合/数组, 通常是构建在IN运算符条件中。

foreach元素:

collection属性:表示对哪一个集合或数组做迭代

如果参数是数组类型,此时Map的key为array;

如果参数是List类型,此时Map的key为list;

open属性:在迭代集合之前,拼接什么符号

close属性:在迭代集合之后,拼接什么符号

separactor属性:在迭代元素时,每一个元素之间使用什么符号分割开来

item属性:被迭代的每一个元素的变量

index属性:迭代的索引

    /**

    * 使用foreach元素批量删除

    * @param ids

    * param注解原理还是Map,Map的key

    */

    void batchDelete(@Param("ids") Long[] ids);

    /**

    * 批量插入用户信息

    * @param list

    * @return

    * 当参数是数组或集合时,一般要加上@Param注解,写死

    */

    int batchInsert(@Param("emps") List<Employee> emps);

    <!--使用foreach元素_完成批量删除-->

    <delete id="batchDelete">

        DELETE FROM employee WHERE id IN

        <foreach collection="ids" open="(" close=")" separator="," item="id">

            #{id}

        </foreach>

    </delete>

    <!--使用foreach元素_完成批量插入-->

    <insert id="batchInsert">

        INSERT INTO employee(id, name, sn, salary, deptId) VALUES

        <foreach collection="emps" separator="," item="e">

            (#{e.id}, #{e.name}, #{e.sn}, #{e.salary}, #{e.deptId})

        </foreach>

    </insert>

    /**

    * 批量删除指定id的员工信息

    */

    @Test

    public void test5(){

        SqlSession sqlSession = MybatisUtils.getSqlSession();

        EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);

        mapper.batchDelete(new Long[]{10L,20L,30L});

        sqlSession.commit();

        sqlSession.close();

    }

    /**

    * 批量插入员工信息

    */

    @Test

    public void test6(){

        SqlSession sqlSession = MybatisUtils.getSqlSession();

        EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);

        List<Employee> list = new ArrayList<Employee>();

        list.add(new Employee(null, "周", "10001", new BigDecimal("5555.00"), 50L));

        list.add(new Employee(null, "吴", "10002", new BigDecimal("6666.00"), 60L));

        list.add(new Employee(null, "郑", "10003", new BigDecimal("7777.00"), 70L));

        int count = mapper.batchInsert(list);

        if (count > 0){

            System.out.println("成功插入了:"+count+"条用户信息!");

        }

        sqlSession.commit();

        sqlSession.close();

    }

7、sql、include、bind

使用sql可以把相同的sql片段起一个名字,并使用include在sql任意位置使用

bind: 使用OGNL表达式创建一个变量,并将其绑定在上下文中

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

<!DOCTYPE mapper

        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--命名空间,类似包的概念: namespace:绑定一个对应的Dao/Mapper接口-->

<mapper namespace="com.sunny.dao.EmployeeMapper">

    <!--多个查询共同使用的sql-->

    <sql id="Base_where">

        <where>

            <if test="keyword!=null">

                <bind name="keywordLike" value="'%' + keyword +'%'"/>

                AND (name LIKE #{keywordLike} OR sn LIKE #{keywordLike})

              <!--AND (name LIKE concat('%', #{keyword}, '%') OR sn LIKE concat('%', #{keyword}, '%'))-->

            </if>

            <if test="minSalary!=null">

                AND salary >= #{minSalary}

            </if>

            <if test="maxSalary!=null">

                AND salary <= #{maxSalary}

            </if>

            <if test="deptId!=null">

                AND deptId = #{deptId}

            </if>

        </where>

    </sql>

    <!--根据查询条件来查询符合条件的查询-->

    <select id="queryForList" resultType="Employee">

        SELECT * FROM employee

        <include refid="Base_where"></include>

    </select>

    <!--查询符合条件的员工数量-->

    <select id="queryForEmpCount" resultType="int">

        SELECT count(*) FROM employee

        <include refid="Base_where"></include>

    </select>

</mapper>

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,776评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,527评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,361评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,430评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,511评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,544评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,561评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,315评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,763评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,070评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,235评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,911评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,554评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,173评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,424评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,106评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,103评论 2 352