MyBatis学习 | 动态SQL

24 篇文章 0 订阅


学习地址🔗

一、简介

💬概述:动态SQL——Dynamic SQL,是MyBatis中强大功能之一,可以根据不同条件来拼接SQL语句

🔑实现动态SQL的几个重要标签

  • if
  • choose(when、otherwise)
  • trim(where、set)
  • foreach

🔑关于动态SQL中使用到的表达式语言——OGNL

  • 全称:Object Graph Navigation Language,对象图导航语言

  • 概述:一种强大的表达式语言,使用它可以方便地操作对象属性,类似于EL表达式

  • 使用

    作用表达式
    访问对象属性person.name
    调用方法person.getName()
    调用静态属性@java.lang.Math@PI
    调用静态方法@java.util.UUID@randomUUID
    调用构造方法new com.key.mybatis.entity.Person(“Key”).name
    算术运算符+,-,*,/,%等
    逻辑运算符in,not in,and,or,<,>,=,<=,>=,!=,==等
    拼接字符串‘str1’ + ‘str2’

    💡 在xml文件中,某些敏感字符需要使用其转移字符代替,如逻辑运算符中<>


二、if标签

2.1 if标签的简单使用

💬概述:在SQL映射文件的SQL标签中,可以添加<if>子标签,根据设置的条件动态拼接SQL语句

🔑作用:根据设置的条件动态直接拼接SQL语句,不进行修剪,一般用于动态拼接WHERE子句的查询条件

🔑属性——text(必须设置)

  • 作用:使用OGNL表达式来设置条件
  • 属性值:OGNL表达式

🔑使用:直接在SQL语句标签内添加<if>,并添加text属性设置条件,<if>标签体内添加动态的语句,当满足text中设置的条件时才会拼上该语句

<!-- id不为null时使用id查询用户信息 -->
<if text="userid != null">
    `user_id` = #{userid}
</if>

💡 text的属性值(OGNL表达式)中的userid对应#{Key}中的键Key,即获取参数时的键,需要根据键获取参数值后再来判断是否为null,不是数据库表中的字段名user_id

🔑测试:使用不为null的参数(字段)来查询对应用户信息

  • 分析:在书写SQL语句时,不能直接知道传进来的参数值哪一个为null,所以需要对查询的条件进行动态拼接

  • 用户持久层接口中添加对应方法

    // 根据if标签的条件来查询用户信息
    List<User> getUsersByIfCondition(User user);
    
  • 用户映射文件

    <!-- 根据if标签条件查询 -->
    <select id="getUsersByIfCondition" resultType="com.key.mybatis.entity.User">
        select *
        from `user`
        where
        <!-- 使用if标签动态拼接查询条件 -->
    
        <!-- id不为null,用id查询 -->
        <if test="userid != null">
            `user_id` = #{userid}
        </if>
        <!-- 姓名不为null,用姓名查询 -->
        <if test="username != null and username.trim() != ''">
            and `user_name` = #{username}
        </if>
        <!-- 密码不为null,用密码查询 -->
        <if test="password != null">
            and `password` = #{password};
        </if>
    </select>
    

    💡 因为持久层接口的对应方法中形参为User,即POJO,所以在映射文件中可以直接将User类的属性名作为键Key获取参数值

  • 测试方法1.0——只有用户id不为null,则只根据用户id查询

    • 方法

      // 创建一个用户对象,只有用户id不为null
      User user = new User(2, null, null);
      
      // 调用持久层接口方法
      List<User> users = mapper.getUsersByIfCondition(user);
      users.forEach(System.out :: println);
      
    • 打印结果test-if-condition-result01

  • 测试方法2.0——用户姓名为null,id和密码不为null,则根据id和密码来查询

    • 方法

      // 创建一个用户对象,用户姓名为null,id和密码不为null
      User user = new User(2, null, "12444");
      
      // 调用持久层接口方法
      List<User> users = mapper.getUsersByIfCondition(user);
      users.forEach(System.out :: println);
      
    • 打印结果test-if-condition-result02

  • 测试方法3.0——用户id和密码都为null,只有姓名不为null,根据姓名查询

    • 方法

      // 创建一个用户对象,用户id和密码都为null,只有姓名不为null
      User user = new User(null, "周慧敏", null);
      
      // 调用持久层接口方法
      List<User> users = mapper.getUsersByIfCondition(user);
      users.forEach(System.out :: println);
      
    • 打印结果test-if-condition-result-error

    • ❌报错原因分析:

      ① 在id为null且姓名不为null情况下,判断id是否为null的<if>标签体内的查询条件(user_id = #{userid})就不会拼接到SQL语句中,姓名对应的<if>标签体内容会完整拼接到SQL语句中

      ② 姓名对应的<if>标签体内容是and user_nam = #{username},查询条件前面还多了个and,而它前面已经没有其他查询条件可以拼接,因此最终拼接而成的SQL语句中,where和查询条件之间也会多一个and,该SQL语句很明显不合法,因此报错if-condition-error-reason

      🔺 解决方法

      ① 在每一个<if>标签体内的查询条件前面都加上and,然后在where子句后加上一个1=1的条件,这样就能保证where子句后面拼上的是条件1=1,而不是多余的and,而且条件1=1恒成立,不会对后面通过and拼起来的查询条件有任何影响,但这种方法仅适用于通过与and连接的查询条件
      ② 使用<where>标签👇

2.2 where标签

❓ 问题引入:在上面对<if>标签的测试方法3.0中,遇到拼接后的SQL语句不合法的问题,如果只使用<if>标签动态拼接SQL语句中的查询条件,就很难避免这个问题,因此需要使用<where>标签来解决(MyBatis推荐)

💬概述<where>也是<select>标签的子标签,它能代替查询SQL语句的where子句

🔑作用:代替where子句,将查询条件作为其标签体内容,使查询条件也能动态拼接,即将合法的查询条件前面多余的内容去掉,剩下合法、有用的内容拼接到where子句后

🔑使用限制<where>只能去掉查询条件前面多余的内容,如果多余的内容在合法查询条件的后面,则无法去掉

🔑测试1.0:传入的用户id和密码都为null,只有姓名不为null,则根据姓名查询用于信息(上面的测试3.0)

  • dao方法不变

    List<User> getUsersByIfCondition(User user);
    
  • 用户映射文件

    <!-- 根据if标签条件查询 -->
    <select id="getUsersByIfCondition" resultType="com.key.mybatis.entity.User">
        select *
        from `user`
    
        <!-- 使用where标签代替where子句
    		 - where标签代替了where子句,因此where就不用再添加
    		 - if标签放在where标签里面
    	-->
        <where>
            <!-- id不为null,用id查询 -->
            <if test="userid != null">
                `user_id` = #{userid}
            </if>
            <!-- 姓名不为null,用姓名查询 -->
            <if test="username != null and username.trim() != ''">
                and `user_name` = #{username}
            </if>
            <!-- 密码不为null,用密码查询 -->
            <if test="password != null">
                and `password` = #{password};
            </if>
        </where>
    </select>
    
  • 测试方法

    // 创建一个用户对象,姓名为null
    User user = new User(null, "周星驰", null);
    
    // 调用持久层接口方法
    List<User> users = mapper.getUsersByIfCondition(user);
    users.forEach(System.out :: println);
    
  • 打印结果test-if-condition-where-result

🔑测试2.0:修改<if>标签中查询内容的书写,将and放在合法的查询条件后面

  • dao方法与测试方法与上面👆一样

  • 映射文件中

    <!-- 根据if标签条件查询 -->
    <select id="getUsersByIfCondition" resultType="com.key.mybatis.entity.User">
        select *
        from `user`
    
        <!-- 使用where标签代替where子句 -->
        <where>
            <!--  
    			* 注意这里的查询条件中,将'and'放到后面
    		-->
            
            <!-- id不为null,用id查询 -->
            <if test="userid != null">
                `user_id` = #{userid} and
            </if>
            <!-- 姓名不为null,用姓名查询 -->
            <if test="username != null and username.trim() != ''">
                `user_name` = #{username} and
            </if>
            <!-- 密码不为null,用密码查询 -->
            <if test="password != null">
                `password` = #{password};
            </if>
        </where>
    </select>
    
  • 打印结果test-if-condition-where-result-error

  • 分析结果:有打印结果可知,<where>标签不会将合法的查询条件后面多余的内容去掉,只能去掉前面的,因此最终拼接而成的SQL语句后面还是会有一个多余的and,这也是不合法的SQL语句,因此也报错

2.3 trim标签(了解)

❓ 问题引入:在上面的测试2.0中,可以看到<where>使用限制——查询条件中多余的内容只能放在前面,如果放在后面就无法去掉,因此最终得到的SQL语句仍然是不合法的,此时可以使用<trim>标签解决

💬概述<trim>也是SQL语句标签的子标签,与<where>标签使用类似

🔑作用:trim是修剪的意思,也是将查询条件作为其标签体内容,对查询条件中的前缀后缀内容进行修改后再拼接到最终的SQL语句中,因此合法查询条件的前面和后面的多余内容都能去掉

🔑 <trim>中四个属性

属性名作用
prefix指定拼接后查询条件的前缀
suffix指定拼接后查询条件的后缀
prefixOverrides指定需要覆盖(去掉)的拼接后查询条件的前缀
suffixOverrides指定需要去掉的拼接后查询条件的后缀

💡 这里的“拼接后查询条件”是指直接拼接而成、没有被修饰过的拼接结果,可能会带有多余的前缀和后缀

🔑测试:将<if>标签中的and放在合法的查询条件后面,作为后缀,且不添加where子句和<where>标签(在<where>标签测试2.0基础上修改)

  • dao方法和测试方法都与上面👆一样

  • 映射文件

    <!-- 根据if标签条件查询 -->
    <select id="getUsersByIfCondition" resultType="com.key.mybatis.entity.User">
        select *
        from `user`
    
        <!-- 使用trim标签,修改查询条件的前后缀
     		 - prefix="where":表示在拼接后的查询结果前加上 where
    		 - suffixOverrides="and":表示去掉拼接后的查询条件后面的 and
    	-->
        <trim prefix="where" suffixOverrides="and">
            <!-- id不为null,用id查询 -->
            <if test="userid != null">
                `user_id` = #{userid} and
            </if>
            <!-- 姓名不为null,用姓名查询 -->
            <if test="username != null and username.trim() != ''">
                `user_name` = #{username} and
            </if>
            <!-- 密码不为null,用密码查询 -->
            <if test="password != null">
                `password` = #{password};
            </if>
        </trim>
    </select>
    
  • 打印结果test-if-condition-trim-result


三、choose标签 & set标签

3.1 choose标签

💬概述<choose>标签也是SQL语句标签的子标签,表示分支选择的意思,与switch...case使用类似

🔑作用:选择出符合指定条件的唯一内容,即只选择出一种情况

🔑子标签<choose>标签中无属性,但有两个重要的子标签

子标签名属性解释是否必须添加
whentext:使用OGNL表达式指定选择的条件指定选择的条件,标签体为选择的内容;类似于case;MyBatis会根据<when>标签的添加顺序来匹配条件,一旦有一个满足条件,就不会再匹配后面的<when>标签条件
otherwise指定默认选择的内容,当所有<when>中指定条件都不满足时就选择<otherwise>标签体中的内容,类似于default

🔑使用:直接在SQL语句标签中添加<choose>子标签,然后在<choose>中再添加<when>标签指定选择的条件,根据需要添加<otherwise>标签指定默认选择

<!-- 使用choose根据条件选择其中一种情况 -->
<choose>
    <when test="userid != null">
        `user_id` = #{userid}
    </when>
    <when test="username != null">
        `user_name` like #{username}
    </when>
    <!-- 默认选择,如果when条件都不满足,就查询全部信息 -->
    <otherwise>
        1=1
    </otherwise>
</choose>

💡 因为<choose>标签只会选择出一种情况,因此每一个<when>标签体内的查询条件中不用添加连接词(andor

🔑测试:查询用户信息,如果id不为null就只用id查询,如果id为null就只用姓名模糊查询,如果姓名也为空就只用密码查询,如果都为null,则就直接将所有用户信息查出

  • 用户dao接口方法

    List<User> getUsersByChooseCondition(User user);
    
  • 用户映射文件

    <!-- 根据choose标签查询 -->
    <select id="getUsersByChooseCondition" resultType="com.key.mybatis.entity.User">
        select *
        from `user`
        <!-- 以后都写where标签 -->
        <where>
            <!-- 使用choose根据条件选择其中一种情况 -->
            <choose>
                <when test="userid != null">
                    `user_id` = #{userid}
                </when>
                <!-- 姓名是模糊查询,用like关键字 -->
                <when test="username != null and username.trim() != ''">
                    `user_name` like #{username}
                </when>
                <when test="password != null">
                    `password` = #{password}
                </when>
                <!-- 默认选择,如果when条件都不满足,就查询全部信息 -->
                <otherwise>
                    1=1
                </otherwise>
            </choose>
        </where>
    </select>
    
  • 测试方法:id为null,用户姓名带有‘周’字,密码11baa

    @Test
    public void testChooseCondition() {
        // 获取SqlSession
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
    
        // 获取mapper对象
        UserDao mapper = sqlSession.getMapper(UserDao.class);
    
        // 创建一个用户对象,id为null,用户姓名带有‘周’字,密码11baa
        User user = new User(null, "%周%", "11baa");
    
        // 调用dao方法
        List<User> users = mapper.getUsersByChooseCondition(user);
    
        users.forEach(System.out :: println);
    
        // 关闭sqlSession
        sqlSession.close();
    }
    
  • 打印结果test-choose-condition-result

    🔺 结果分析:由打印结果可以看出,最终拼出的SQL语句中只有根据姓名模糊查询的条件,即使传入的参数中密码’password’也不为null,但密码对应的<when>选择条件在姓名后面,因此就不会去匹配密码对应的<when>选择条件

3.2 set标签

💬概述<set>标签是<update>标签中的子标签,用于代替更新SQL语句中的set子句

🔑作用:代替更新语句中的set子句,选择性拼接set后面的更新内容,可以去掉拼接后的多余内容,一般是,

🔑使用:在<update>标签中添加<set>标签,代替set子句,同时使用<if>根据指定条件动态获取更新内容

<!-- 使用set标签动态拼接更新内容 -->
<set>
    <!-- 使用if标签动态获取更新内容 -->
    <if test="username != null">
        `user_name` = #{username},
    </if>
    <if test="password != null">
        `password` = #{password}
    </if>
</set>

❓ 关于去掉拼接后的多余内容

  • 如果更新语句中不使用<set>标签,而是直接使用set子句和<if>标签动态拼接更新内容,则最终拼接的SQL语句有可能在后面多了个,,造成SQL语句不合法。与<where>解决的情况类似
  • 对于去掉多余的拼接内容,一样能使用<trim>标签来实现,此时需要添加的前缀prefix="set",需要去掉的后缀suffixOverrides=","(不推荐使用)

🔑测试:修改id为5的用户信息,只修改不为null的字段信息

  • 用户dao接口方法

    int updateUserBySetCondition(User user);
    
  • 用户映射文件

    <!-- 使用set标签更新用户信息 -->
    <update id="updateUserBySetCondition">
        update `user`
        <!-- 使用set标签动态拼接更新内容 -->
        <set>
            <!-- 使用if标签动态获取更新内容 -->
            <if test="username != null">
                `user_name` = #{username},
            </if>
            <if test="password != null">
                `password` = #{password}
            </if>
        </set>
        <!-- 最后还有查询条件的拼接,使用where -->
        <where>
            `user_id` = #{userid}
        </where>
    </update>
    
  • 测试方法

    @Test
    public void testSetCondition() {
        // 获取SQlSession
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
    
        // 获取mapper
        UserDao mapper = sqlSession.getMapper(UserDao.class);
    
        // 创建一个用户对象
        User user = new User(5, "周海媚", null);
    
        // 调用dao方法
        int result = mapper.updateUserBySetCondition(user);
    
        if (result == 0) {
            System.out.println("更新失败!");
        } else {
            System.out.println("更新成功!");
        }
    
        // 提交事务
        sqlSession.commit();
    
        // 关闭sqlSession
        sqlSession.close();
    }
    
  • 打印结果test-set-condition-result


四、foreach标签

4.1 foreach标签的简单使用

💬概述<foreach>标签也是SQL语句标签的一个子标签,可以实现循环遍历的功能

🔑作用:循环遍历指定的数组或集合,并将遍历后的结果拼接到SQL语句中

🔑属性<foreach>有下列主要属性

属性名属性值解释是否必须添加
collection属性值为需要遍历的集合名称,对应dao接口方法集合类型形参标识出<foreach>中所遍历的集合或数组;如果在dao接口方法中没有为形参命名,则collection属性值只能使用默认键——【argN、collection、list]
item自定义的变量名标识当前遍历的元素,通过该属性值能获取每一个元素以及每一个元素的属性
separator自定义的分隔符为遍历的集合或数组的每一项之间添加一个分割符
open自定义字符为循环结束后拼接的语句前面添加一个开始字符
close自定义字符为循环结束后拼接的语句后面添加一个结束字符
index自定义的变量名①如果遍历的是List集合或数组,则该属性就是每一项的索引值;②如果遍历的是Map集合,则该属性就是Map中的键Key

🔑使用

  • 在SQL语句标签中添加<foreach>标签,<foreach>标签内添加相关属性
  • 使用#{}${}获取集合中每一项的值
<foreach collection="ids" item="uId" separator="," open="(" close=")">
    #{uId}
</foreach>

🔑测试:查询id为1-4之间的用户信息

  • 分析

    • 查询不同id的用户信息,可以使用in ()语句来实现,而()里面的各个id可以封装成一个id集合,然后再SQL语句中遍历出来即可
    • dao接口方法中为形参命名,在映射文件取参数时就可以直接通过自定义名来获取
    • 因为()里面的不同参数之间用,隔开,因此在<foreach>遍历时也需要使用separator属性为每一项之间添加分隔符,不能在循环体中直接写,,因为这样写会使遍历的最后一项后面也有一个,,从而造成SQL语句不合法
    • 因为要遍历的集合在()里面,即<foreach>遍历结束后拼接的内容添加到()里面,有两种实现方式
      ① 将左括号(写在在<foreach>前面,右括号)写在后面,相当于用()<foreach>包裹起来
      ② 使用<foreach>标签中的openclose属性,为循环遍历结束后拼接的内容前面加上开始字符(,后面加上结束字符)(推荐)
  • 用户dao接口方法

    List<User> getUsersByForeachCondition(@Param("ids") List<Integer> ids);
    
  • 用户映射文件

    <!-- 根据指定的id集合查询出对应的用户信息 -->
    <select id="getUsersByForeachCondition" resultType="com.key.mybatis.entity.User">
        select *
        from `user`
        <where>
            `user_id` in
            <foreach collection="ids" item="uId" separator="," open="(" close=")">
                #{uId}
            </foreach>
        </where>
    </select>
    
  • 测试方法

    @Test
    public void testForeachCondition() {
        // 获取SqlSession
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
    
        // 获取mapper
        UserDao mapper = sqlSession.getMapper(UserDao.class);
    
        // 调用dao方法
        List<User> users = mapper.getUsersByForeachCondition(Arrays.asList(1, 2, 3, 4));
    
        users.forEach(System.out :: println);
    
        // 关闭sqlSession
        sqlSession.close();
    }
    

    💡 测试中直接使用工具类的方法创建id集合——Arrays.asList()

  • 打印结果test-foreach-condition-result

4.2 批量插入

💡 下面只针对MySQL数据库支持的批量插入方式

💬概述:使用<foreach>标签还可以遍历多个对象记录,实现向数据库表中批量插入多条记录

🔑批量插入方式1.0——在插入SQL语句中的values后添加多个(),多个()之间用,分隔开

  • 用户dao接口方法

    int batchInsertUsersByForeach(@Param("users") List<User> users);
    
  • 用户映射文件

    <!-- 批量插入多条用户记录1.0 -->
    <insert id="batchInsertUsersByForeach">
        insert into `user`(`user_name`, `password`)
        values
        <!-- 使用foreach循环遍历每一条插入数据 -->
        <foreach collection="users" item="u" separator=",">
            (#{u.username}, #{u.password})
        </foreach>
    </insert>
    

    💡 这里是将()写在<foreach>标签体(循环体)中,因为要遍历的每一项包含了(),而不是每一项在()

  • 测试方法

    @Test
    public void testBatchInsertByForeach() {
        // 获取SqlSession
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
    
        // 获取mapper
        UserDao mapper = sqlSession.getMapper(UserDao.class);
    
        // 创建一个用户集合
        List<User> users = new ArrayList<>();
        users.add(new User(null, "宋江", "song123"));
        users.add(new User(null, "武松", "wu123"));
        users.add(new User(null, "潘金莲", "pan123"));
    
        int result = mapper.batchInsertUsersByForeach(users);
    
        if (result == 0) {
            System.out.println("批量插入失败!");
        } else {
            System.out.println("批量插入成功!");
        }
    
        // 提交事务
        sqlSession.commit();
    
        // 关闭
        sqlSession.close();
    }
    
  • 打印结果test-foreach-batch-insert-result01

🔑批量插入方式2.0——直接执行多次insert语句,每条insert语句之间用;分隔开

  • 用户dao接口方法同上

  • 用户映射文件

    <!-- 批量插入2.0 -->
    <insert id="batchInsertUsersByForeach">
        <!-- 直接使用foreach遍历多次insert语句,每条语句之间用;隔开 -->
        <foreach collection="users" item="u" separator=";">
            insert into `user`(`user_name`, `password`)
            values(#{u.username}, #{u.password})
        </foreach>
    </insert>
    
  • 在jdbc属性文件中添加allowMultiQueries参数,并设置为true

    prop.url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
    

    💡 此操作必不可少,因为参数allowMultiQueries默认为false,即MySQL默认不支持多条SQL语句通过;分隔开并同时执行

  • 测试方法

    // 创建一个用户集合
    List<User> users = new ArrayList<>();
    users.add(new User(null, "吴用", "wu456"));
    users.add(new User(null, "武大郎", "da123"));
    users.add(new User(null, "扈三娘", "hu123"));
    
    int result = mapper.batchInsertUsersByForeach(users);
    
    if (result == 0) {
        System.out.println("批量插入失败!");
    } else {
        System.out.println("批量插入成功!");
    }
    
  • 打印结果test-foreach-batch-insert-result02


五、内置参数

💬概述:MyBatis中不仅可以获取dao接口方法传递过来的参数值,还能使用内置参数来获取值,且在OGNL表达式中可以直接使用内置参数

🔑两个内置参数

  • _parameter

    • 概述

      ① 如果dao接口只传入单个简单类型的形参,则_parameter就表示这个形参,可以直接根据它来获取对应参数值;② 如果形参中传入多个参数,MyBatis会将dao接口方法中的形参封装成一个Map集合,而内置参数_parameter就表示这个Map集合

    • 作用:表示任意传进来的单个参数或参数Map集合,可以直接获取对应参数值

    • 使用:在<if>标签的text属性中判断传入的形参是否为null,如果不为null才获取对应参数

      <!-- 直接根据内置参数_parameter判断传入形参是否为null -->
      <if text="_parameter != null">
      	where `user_id` = #{userid}
      </if>
      
    • 使用细节

      1. _parameter一般使用在判断条件中(如果<if>标签的text属性里面),即OGNL表达式中,不使用在#{}获取参数
      2. 如果传入单个对象类型的形参,则可以直接使用_parameter.属性名来获取对象的属性值
      3. 如果传入多个形参,则可以使用_parameter.键Key的方式来获取对应参数值,包括默认键——argN和paramN
      4. 如果传入单个普通类型参数,则可以直接使用_parameter就能获取到参数值,或者使用_parameter.键Key
  • _databaseId

    • 概述:如果全局配置文件中设置了<databaseIdProvider>标签,并为各个数据库厂商标识设置了别名,则内置参数_databaseId就表示当前环境下数据库厂商标识的别名

    • 作用:可以直接在SQL语句标签体中获取当前环境的数据库厂商标识,并可以根据不同环境下的数据库厂商设置不同的SQL语句

    • 使用:在<if>标签的text属性中判断当前环境的数据库厂商,然后使用对应的SQL语句

      <!-- 根据数据库厂商标识的别名来选择查询数据库表 -->
      <if test="_databaseId == 'mysql'">
          <!-- mysql下查询user表 -->
          select * from `user`
      </if>
      <if test="_databaseId == 'oracle'">
          <!-- oracle下查询employeeb -->
          select * from `employee`
      </if>
      

六、bind标签

💬概述<bind>也是SQL语句标签的子标签,bind是绑定的意思,顾名思义就是用来绑定数据或值

🔑作用:使用<bind>标签,可以为自定义的值绑定一个变量名,根据变量名就能获取到对应的值

🔑<bind>标签的两个属性

属性名属性值解释
name自定义的变量名为自定义的新参数绑定一个变量名,SQL语句中通过#{Key}获取参数值时,就可以直接将该变量名作为键Key来获取新的参数值
value自定义的新参数value属性中可以使用OGNL表达式来自定义新的参数,比如可以直接根据键Key获取传进来的形参对应的参数值,然后将参数值修改成新的参数

🔑使用:根据姓名模糊查询用户信息,模糊查询时直接传入关键字,不传入通配符(%_),在映射文件中再为传入的关键字添加上通配符,形成一个新参数,然后使用<bind>为该新参数绑定一个变量名,SQL语句中根据该变量名来获取对应参数值

  • dao接口方法

    List<User> listUsersByBind(String nameKey);
    
  • 映射文件

    <!-- 根据姓名关键字模糊查询 -->
    <select id="listUsersByBind" resultType="com.key.mybatis.entity.User">
        <!-- 使用bind标签绑定新的参数 
    		 - name="newName":为自定义的新参数绑定一个变量名
    		 - value="...":自定义新的参数,也是使用OGNL表达式
    	-->
        <bind name="newName" value="'%' + nameKey + '%'"/>
        select *
        from `user`
        where `user_name` like #{newName};
    </select>
    
  • 测试方法

    @Test
    public void testBind() {
        // 获取SqlSession
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
    
        // 获取mapper
        UserDao mapper = sqlSession.getMapper(UserDao.class);
    
        List<User> users = mapper.listUsersByBind("周");
    
        users.forEach(System.out :: println);
    
        // 关闭sqlSession
        sqlSession.close();
    }
    

七、sql标签 & include标签

🔑sql标签

  • 概述:<sql>标签是与其他SQL语句标签同级的标签,在<sql>标签中也能书写SQL语句
  • 作用:抽取可重用的SQL语句,一般用于抽取插入语句、更新语句时的数据库表的列名
  • 使用细节:<sql>标签中也可以使用动态SQL语句中各种条件标签,如<if><where>
  • 属性——id:唯一标识,根据sql-id可以引用其抽取的SQL语句

🔑include标签

  • 概述:<include>标签是SQL语句标签的子标签,与<sql>标签是合作伙伴

  • 作用:引用<sql>中抽取的可重用SQL语句

  • 作用位置:穿插在SQL语句中,取代被抽取的部分SQL语句

  • 使用细节:在<include>标签中还可以通过<property>子标签自定义属性<sql>标签中就可以使用${}获取对应属性

    💡 <sql>标签中获取<include>定义的属性时,只能使用${},不能使用#{}

  • 属性——refid:对应<sql>标签中的唯一标识sql-id,根据该id标识了对应<sql>标签后,<include>所在的位置就会被<sql>中抽取的SQL语句所代替,最终拼接成完整的SQL语句

🔑sql标签和include标签结合使用

  • 使用1.0——使用<sql>抽取插入语句中的各个数据库表列名,然后在SQL语句标签中使用<include>引用对应SQL

    <!-- 使用sql标签和include标签 -->
    <insert id="insertUserBySqlAndInclude">
        insert into `user` (
        	<!-- include标签直接写在SQL语句中,取代抽取的SQL -->
        	<include refid="insertColumn"/>
        )
        values(#{userid}, #{username}, #{password})
    </insert>
    
    <!-- 抽取可重用SQL语句 -->
    <sql id="insertColumn">
        `user_name`, `password`
    </sql>
    
  • 使用2.0——在<include>中为密码字段’password’再自定义一个名称,然后在<sql>中使用自定义名来获取对应字段名

    <!-- 使用sql标签和include标签 -->
    <insert id="insertUserBySqlAndInclude">
        insert into `user` (
            <include refid="insertColumn">
                <!-- 自定义属性 -->
                <property name="pwd" value="password"/>
            </include>
        )
        values(#{userid}, #{username}, #{password})
    </insert>
    
    <!-- 抽取可重用SQL语句 -->
    <sql id="insertColumn">
        <!-- 使用${}获取include设置的属性值 -->
        `user_name`, ${pwd}
    </sql>
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值