精华内容
下载资源
问答
  • 动态SQL标签

    2021-05-09 15:09:55
    if标签可以动态判断属性值,进而动态拼接查询条件 where标签在缺少查询条件的时候,会自动的去除前面的AND连接 <mapper namespace="dao.TeacherDao"> <select id="getTeacherById" resultMap="teacherMap...

    一、if标签、where标签

    if标签可以动态判断属性值,进而动态拼接查询条件

    where标签在缺少查询条件的时候,会自动的去除前面的AND连接

    <mapper namespace="dao.TeacherDao">
        <select id="getTeacherById" resultMap="teacherMap">
            SELECT  * FROM teacher WHERE id = #{id}
        </select>
    
        <resultMap id="teacherMap" type="bean.Teacher">
            <id property="id" column="id"></id>
            <result property="name" column="teacherName"></result>
            <result property="subject" column="subject_name"></result>
            <result property="address" column="address"></result>
            <result property="birth" column="birth_date"></result>
        </resultMap>
    
        <!--if标签进行判断-->
        <select id="getTeachersByCondition" resultMap="teacherMap">
            SELECT  * FROM teacher
            <where>
                <!--test编写判断条件-->
                <if test="id != null">
                    id > #{id} AND
                </if>
                <if test="name != null and name != ''">
                    teacherName LIKE #{name} AND
                </if>
                <if test="birth != null">
                    birth_date > #{birth}
                </if>
            </where>
        </select>
    
    </mapper>
    
        @Test
        public void test10() throws IOException {
            //1、根据全局配置文件创建出一个SQLSessionFactory
            //SqlSessionFactory是SqlSession工厂,负责创建SqlSession对象
            //SqlSession是sql会话,代表和数据库的一次会话
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    
            Teacher teacher = null;
            SqlSession sqlSession = null;
    
            try {
                //2.获取和数据库的一次会话,类似于getConnection()方法
                sqlSession = sqlSessionFactory.openSession();
    
                //3、使用SqlSession操作数据库,获取到dao接口的实现
                TeacherDao teacherDao = sqlSession.getMapper(TeacherDao.class);
    
                //4、调用接口中的方法
                teacher = new Teacher();
                teacher.setId(1);
                teacher.setName("%老%");
                teacher.setBirth(new Date());
                List<Teacher> teachersByCondition = teacherDao.getTeachersByCondition(teacher);
                System.out.println(teachersByCondition);
    
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
    
                //默认自动提交为false,所以需要手动提交
                sqlSession.commit();
    
                //关闭会话
                sqlSession.close();
            }
    
        }
    

    输出结果:
    在这里插入图片描述

    二、trim标签

        <!--if标签进行判断-->
        <select id="getTeachersByCondition" resultMap="teacherMap">
            SELECT  * FROM teacher
            <!--trim截取字符串
                prefix: 为slq整体添加一个前缀
                prefixOverrides:去除整体字符串前面多余的字符
                suffix:为整体sql字符串添加一个后缀
                suffixOverrides:去除整体字符串后面多余的字符
            -->
            <trim prefix="where" suffixOverrides="and">
                <!--test编写判断条件-->
                <if test="id != null">
                    id > #{id} AND
                </if>
                <if test="name != null and name != ''">
                    teacherName LIKE #{name} AND
                </if>
                <if test="birth != null">
                    birth_date > #{birth} AND
                </if>
            </trim>
        </select>
    

    三、foreach标签

        <select id="getTeachersByIds" resultMap="teacherMap">
            SELECT * FROM teacher WHERE id IN
            <!--foreach遍历集合
                Collection指定遍历的集合的key
                 close="": 以什么字符结束
                 index="" :如果遍历的是list,index是指定的变量保存了当前的索引;  如果遍历的是一个map,index是指定的变量保存了当前遍历的元素的key,item就是保存了当前遍历的元素的值
                 item="" :每次遍历的变量名
                 open="" :以什么字符开始
                 separator="":指定元素之间的分隔符
            -->
            <foreach collection="ids" item="id_item" separator="," open="(" close=")"><!--需要在接口方法中指明(@Param("ids") List<Integer> ids)-->
                #{id_item}
            </foreach>
        </select>
    
        @Test
        public void test11() throws IOException {
            //1、根据全局配置文件创建出一个SQLSessionFactory
            //SqlSessionFactory是SqlSession工厂,负责创建SqlSession对象
            //SqlSession是sql会话,代表和数据库的一次会话
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    
            Teacher teacher = null;
            SqlSession sqlSession = null;
    
            try {
                //2.获取和数据库的一次会话,类似于getConnection()方法
                sqlSession = sqlSessionFactory.openSession();
    
                //3、使用SqlSession操作数据库,获取到dao接口的实现
                TeacherDao teacherDao = sqlSession.getMapper(TeacherDao.class);
    
                //4、调用接口中的方法
                List<Teacher> teachers = teacherDao.getTeachersByIds(Arrays.asList(1, 2, 3));
                System.out.println(teachers);
    
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
    
                //默认自动提交为false,所以需要手动提交
                sqlSession.commit();
    
                //关闭会话
                sqlSession.close();
            }
    
        }
    

    输出结果:
    在这里插入图片描述

    四、choose标签

        <select id="getTeachersByConditionChoose" resultMap="teacherMap">
            SELECT * FROM teacher
            <where>
                <choose>
                    <when test="id != null">
                        id = #{id}
                    </when>
                    <when test="name != null and !name.equals(&quot;&quot;)">
                        teacherName = #{name}
                    </when>
                    <when test="birth_date != null">
                        birth_date = #{birth}
                    </when>
                    <otherwise>
                        1=1
                    </otherwise>
                </choose>
            </where>
        </select>
    
        @Test
        public void test12() throws IOException {
            //1、根据全局配置文件创建出一个SQLSessionFactory
            //SqlSessionFactory是SqlSession工厂,负责创建SqlSession对象
            //SqlSession是sql会话,代表和数据库的一次会话
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    
            Teacher teacher = null;
            SqlSession sqlSession = null;
    
            try {
                //2.获取和数据库的一次会话,类似于getConnection()方法
                sqlSession = sqlSessionFactory.openSession();
    
                //3、使用SqlSession操作数据库,获取到dao接口的实现
                TeacherDao teacherDao = sqlSession.getMapper(TeacherDao.class);
    
                //4、调用接口中的方法
                teacher = new Teacher();
                teacher.setId(1);
                teacher.setName("%老师%");
                //使用choose标签只会从id,name,birth选择其中一个作为查询条件
                List<Teacher> teachers = teacherDao.getTeachersByConditionChoose(teacher);
    
                System.out.println(teachers);
    
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
    
                //默认自动提交为false,所以需要手动提交
                sqlSession.commit();
    
                //关闭会话
                sqlSession.close();
            }
    
        }
    

    输出结果:
    在这里插入图片描述

    五、使用if结合set完成MyBatis动态更新

        <update id="updateTeacher">
            UPDATE teacher
            <set>
                <if test="name != null and !name.equals(&quot;&quot;)">
                    teacherName = #{name},
                </if>
                <if test="subject != null and !name.equals(&quot;&quot;)">
                    subject_name = #{subject},
                </if>
                <if test="address != null and !name.equals(&quot;&quot;)">
                    address = #{address},
                </if>
                <if test="birth != null">
                    birth_data = #{birth},
                </if>
    
            </set>
    
            <where>
                id = #{id}
            </where>
    
        </update>
    
                //4、调用接口中的方法
                teacher = new Teacher();
                teacher.setId(1);
                teacher.setName("update动态更新");
                int i = teacherDao.updateTeacher(teacher);
    

    六、sql标签

    抽取可重用的SQL语句,使用include包含进来

        <sql id="selectSql">SELECT  * FROM teacher</sql>
    
    	<select id="getTeacherById" resultMap="teacherMap">
            <include refid="selectSql"></include>
            WHERE id = #{id}
        </select>
    

    七、bind标签

    bind标签可以把一个表达式绑定在一个变量上

                <bind name="_name" value="'%'+name+'%'"></bind>
                <if test="name != null and name != ''">
                    teacherName LIKE #{_name} AND
                </if>
    
    展开全文
  • 动态sql标签

    2019-09-06 09:34:03
    标签里面嵌套<when>和<otherwise>标签,<when>和<otherwise>标签里面有‘test’选项里面可以写判断条件, <choose>标签类似于java中的swith case标签,只要有一个条件满足就判断就...

     1,<choose>标签里面嵌套<when>和<otherwise>标签,<when>和<otherwise>标签里面有‘test’选项里面可以写判断条件, <choose>标签类似于java中的swith  case标签,只要有一个条件满足就判断就终止.

     

    2,<where>标签,常和<if>标签搭配使用,此标签用来填充where关键字,使用标签与使用where关键字的区别是,<where>: 在SQL语句中添加WHERE关键字, 去掉where后面第一个条件前面的 and / or。

     

    3,<foreach>标签  ,用来遍历集合或者数组    ,里面有 collection,item, close,  separator,  index  

    collection,代表需要遍历的集合  如果是List集合, collection内填 list  ,建议使用@param()注解进行参数命名

    item,遍历出来的集合元素

    open, 开始字符

    close,  结束字符

    separator, 分隔符

    index  ,如果是数组或者集合代表下标,  如果是map集合List就是代表map的key

     

    4,<set>标签  在修改的操作中, 去掉SQL语句中多出的逗号。

     

    5,<if>标签,用来动态进行判断条件是否成立,  常常使用 if里面的test属性进行判断  eg:  test= "name != null";

     

    6,   <trim>在判断完的SQL语句的前后 添加内容 或者去掉指定的内容.   里面 包含属性 prefix  suffix   prefixoverride  suffixoverride 这四个标签

    常常在内部搭配<if>标签使用。

    prefix  :添加指定的前缀  

    suffix   :添加指定后缀

    prefixoverride :  去掉第一个指定的前缀  eg: prefixoverride="AND |OR" 

    suffixoverride  : 去掉最后一个指定的后缀  eg: suffixoverride="AND |OR"

    展开全文
  • Mybatis 动态SQL标签

    2020-10-17 09:45:09
    Mybatis 动态SQL标签一、前言二、动态标签2.1 if 元素2.2 choose/when/otherwise 元素2.3 where 元素2.4 set 元素2.5 trim 元素2.6 foreach 元素2.7 sql/include 元素2.8 bind元素三、# 和$ 一、前言 最近面试的时候...

    一、前言

    最近面试的时候被问到了几次Mybatis 的动态标签,有意想做一下整理。
    恰巧在CSDN app 上看到Mybatis系列第十讲 动态SQL,这么多种你都会?一文,个人觉得写得挺全的,故得到该博主的同意,转载至此并略作修改。

    二、动态标签

    数据库准备:

    DROP DATABASE IF EXISTS `javacode2018`;
    CREATE DATABASE `javacode2018`;
    
    USE `javacode2018`;
    
    DROP TABLE IF EXISTS t_user;
    CREATE TABLE t_user(
      id int AUTO_INCREMENT PRIMARY KEY COMMENT '用户id',
      name VARCHAR(32) NOT NULL DEFAULT '' COMMENT '用户名',
      age SMALLINT NOT NULL DEFAULT 1 COMMENT '年龄'
    ) COMMENT '用户表';
    INSERT INTO t_user VALUES (1,'路人甲Java',30),(2,'张学友',50),(3,'刘德华',50);
    

    2.1 if 元素

    相当于java 中的if 判断,语法:

    <if test="判断条件">
    	需要追加的sql
    </if>
    

    test 的值为一个判断表达式,写法上采用OGNL 表达式的方式,OGNL 在struts2 中用的比较多,本文暂时对ognl 不做详细介绍,有兴趣的可以去查一下相关资料。

    当test 成立的时候,if 体内部的sql 会被拼接上。如:

    <select id="getList1" resultType="com.javacode2018.chat05.demo8.model.UserModel" parameterType="map">
        SELECT id,name,age FROM t_user
        WHERE 1 = 1
        <if test="id!=null">
            AND id = #{id}
        </if>
        <if test="name!=null and name.toString()!=''">
            AND name = #{name}
        </if>
        <if test="age!=null">
            AND age = #{age}
        </if>
    </select>
    

    上面查询用户列表,参数为一个map,当map 中id 不为空的时候,将其作为条件查询,如果name 不为空,将name 也作为条件,如果age 不为空,将age 也作为条件进行查询。
    当只传入id 的时候,sql 如下:

    SELECT id,name,age FROM t_user WHERE 1 = 1 AND id = ? 
    

    当3 个参数都传了,sql 如下:

    SELECT id,name,age FROM t_user WHERE 1 = 1 AND id = ? AND name = ? AND age = ?
    

    上面这种写法相对于java 代码看起来是不是清爽了很多,也更方便维护。
    大家注意一下sql 中有个WHERE 1=1,如果没有这个,上面的样例单单通过if 元素就不好实现了,不过mybatis 也有对应的解决方案,稍后会说明。

    2.2 choose/when/otherwise 元素

    这个相当于java 中的if…else if…else,语法:

    <choose>
        <when test="条件1">
            满足条件1追加的sql
        </when>
        <when test="条件2">
            满足条件2追加的sql
        </when>
        <when test="条件n">
            满足条件n追加的sql
        </when>
        <otherwise>
            都不满足追加的sql
        </otherwise>
    </choose>
    
    • choose 内部的条件满足一个,choose 内部的sql 拼接就会结束
    • otherwise 属于可选的,当所有条件都不满足的时候,otherwise 将起效。

    choose 内部条件遵循最近匹配的原则,如:

    传入id、name、age 作为条件,按顺序进行判断,如果id 不为空,将id 作为条件,忽略其他条件;如果id 为空,会判断name 是否为空,name 不为空将name 作为条件;如果name 为空,再看age 是否为空,如果age 不为空,将age 作为条件。

    <select id="getList2" resultType="com.javacode2018.chat05.demo8.model.UserModel" parameterType="map">
        SELECT id,name,age FROM t_user
        WHERE 1 = 1
        <choose>
            <when test="id!=null">
                AND id = #{id}
            </when>
            <when test="name!=null and name.toString()!=''">
                AND name = #{name}
            </when>
            <when test="age!=null">
                AND age = #{age}
            </when>
        </choose>
    </select>
    
    

    如果id、name、age 都传了,sql 如下:

    SELECT id,name,age FROM t_user WHERE 1 = 1 AND id = ? 
    

    如果值传递了name、age,sql 如下:

    SELECT id,name,age FROM t_user WHERE 1 = 1 AND name = ? 
    

    name 的判断条件在age 前面,所以name 条件被匹配上了,其后面的age 条件就自动失效。

    2.3 where 元素

    上面2 个案例的sql 中都有【where 1=1】这部分代码,虽然可以解决问题,但是看起来不美观。但是如果将where 1=1 中1=1 这部分干掉,上面的两个案例又都会出问题,where后面会多一个AND符号。
    对于这个问题,mybatis 中通过where 元素来解决。
    当使用where 元素的时候,mybatis 会将where 内部拼接的sql 进行处理:
    将这部分sql 前面的AND 或者OR 给去掉,并在前面追加一个where。
    我们使用where 元素来对上面的案例1进行改造,如下:

    <select id="getList1" resultType="com.javacode2018.chat05.demo8.model.UserModel" parameterType="map">
        SELECT id,name,age FROM t_user
        <where>
            <if test="id!=null">
                AND id = #{id}
            </if>
            <if test="name!=null and name.toString()!=''">
                AND name = #{name}
            </if>
            <if test="age!=null">
                AND age = #{age}
            </if>
        </where>
    </select>
    

    where 1=1 被替换成了where 元素。

    当传入id、name的时候,where 内部的sql 会变成这样:

    AND id = ? AND name = ?
    

    mybatis 会对上面这个sql 进行处理,将前面的AND 给去掉,并在前面追加一个where,变成了下面这样

    where id = ? AND name = ?
    

    案例2 也用where 改造一下,变成了下面这样:

    <select id="getList2" resultType="com.javacode2018.chat05.demo8.model.UserModel" parameterType="map">
        SELECT id,name,age FROM t_user
        <where>
            <choose>
                <when test="id!=null">
                    AND id = #{id}
                </when>
                <when test="name!=null and name.toString()!=''">
                    AND name = #{name}
                </when>
                <when test="age!=null">
                    AND age = #{age}
                </when>
            </choose>
        </where>
    </select>
    

    这下看起来是不是舒服很多了。

    2.4 set 元素

    现在我们想通过用户id 更新用户信息,参数为UserModel 对象,对象中的属性如果不为空,就进行更新,我们可以这么写:

    <update id="update1" parameterType="com.javacode2018.chat05.demo8.model.UserModel">
        UPDATE t_user SET
        <if test="name!=null">
            name = #{name},
        </if>
        <if test="age!=null">
            age = #{age},
        </if>
        <where>
            <if test="id!=null">
                AND id = #{id}
            </if>
        </where>
    </update>
    

    我们来看一下,当所有属性都传值了,sql 变成了下面这样:

    UPDATE t_user SET name = ?, age = ?, where id = ?
    

    上面这个sql 是有问题的,where 前面多了一个逗号,得想办法将这个逗号去掉,这个逗号属于最后一个需要更新的字段后面的逗号,是多余的。
    mybatis 中提供了set 元素来解决这个问题,将上面的代码改成下面这样:

    <update id="update1" parameterType="com.javacode2018.chat05.demo8.model.UserModel">
        UPDATE t_user
        <set>
            <if test="name!=null">
                name = #{name},
            </if>
            <if test="age!=null">
                age = #{age},
            </if>
        </set>
        <where>
            <if test="id!=null">
                AND id = #{id}
            </if>
        </where>
    </update>
    

    我们将sql 中的set 去掉了,换成了set 元素。set 元素会对其内部拼接的sql 进行处理,会将这部分sql 前后的逗号给去掉并在前面加上set

    当传入id 和age 的时候,生成的sql :

    UPDATE t_user SET age = ? where id = ?
    

    2.5 trim 元素

    这个元素的功能比较强大,先看一下他的语法:

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

    trim 元素内部可以包含各种动态sql,如where、chose、sql 等各种元素,使用trim 包含的元素,mybatis 的处理过程:

    1. 先对trim 内部的sql 进行拼接,比如这部分sql 叫做sql1
    2. 将sql1 字符串前面的部分中包含trim 的prefixOverrides 指定的部分给去掉,得到sql2
    3. 将sql2 字符串后面的部分中包含trim 的suffixOverrides 指定的部分给去掉,得到sql3
    4. 在sql3 前面追加trim 中prefix 指定的值,得到sql4
    5. 在sql4 后面追加trim 中suffix 指定的值,得到最终需要拼接的sql5

    了解了这个过程之后,我们使用trim 来改造一下案例1,如下:

    <select id="getList1" resultType="com.javacode2018.chat05.demo8.model.UserModel" parameterType="map">
        SELECT id,name,age FROM t_user
        <trim prefix="where" prefixOverrides="and|or">
            <if test="id!=null">
                AND id = #{id}
            </if>
            <if test="name!=null and name.toString()!=''">
                AND name = #{name}
            </if>
            <if test="age!=null">
                AND age = #{age}
            </if>
        </trim>
    </select>
    

    注意上面的prefixOverrides 的值的写法,如果有多个需要覆盖的之间用 | 进行分割,suffixOverrides 写法和prefixOverrides 的写法类似。

    我们在用trim 来改造一下上面的update,如下:

    <update id="update1" parameterType="com.javacode2018.chat05.demo8.model.UserModel">
        UPDATE t_user
        <trim prefix="SET" prefixOverrides="," suffixOverrides=",">
            <if test="name!=null">
                name = #{name},
            </if>
            <if test="age!=null">
                age = #{age},
            </if>
        </trim>
        <where>
            <if test="id!=null">
                AND id = #{id}
            </if>
        </where>
    </update>
    

    上面的prefixOverrides 和suffixOverrides 都设置的是逗号,表示trim 内部的sql 前后的逗号会被去掉,最后会在前面拼接一个prefix 指定的set。

    2.6 foreach 元素

    相当于java 中的循环,可以用来遍历数组、集合、map 等。

    语法:

    <foreach collection="需要遍历的集合" item="集合中当前元素" index="" open="" separator="每次遍历的分隔符" close="">
    	动态sql部分
    </foreach>
    
    • collection:可以是一个List、Set、Map 或者数组
    • item:集合中的当前元素的引用
    • index:用来访问当前元素在集合中的位置
    • separator:各个元素之间的分隔符
    • open 和close:用来配置最后用什么前缀和后缀将foreach 内部所有拼接的sql 给包装起来。

    案例:in 多值查询
    我们对案例1 做个改造,map 中支持放入用户的id 列表(ArrayList),对应的key 为idList,然后支持多个用户id 查询,此时我们需要用in 来查询,实现如下:

    <select id="getList1" resultType="com.javacode2018.chat05.demo8.model.UserModel" parameterType="map">
        SELECT id,name,age FROM t_user
        <where>
            <if test="id!=null">
                AND id = #{id}
            </if>
            <if test="name!=null and name.toString()!=''">
                AND name = #{name}
            </if>
            <if test="age!=null">
                AND age = #{age}
            </if>
            <if test="idList!=null and idList.size()>=1">
                <foreach collection="idList" item="id" open="AND id in (" separator="," close=")">
                    #{id}
                </foreach>
            </if>
        </where>
    </select>
    

    大家看一下上面idList 那部分判断,判断这个参数不为空,并且size() 大于1,表示这个集合不为空,然后会使用if 元素内部的foreach 元素。

    比如我们传递的idList 对应的是[1,2],最后产生的sql 如下:

    SELECT id,name,age FROM t_user WHERE id in ( 1 , 2 ) 
    

    案例:批量插入
    传入UserModel List 集合,使用foreach 实现批量插入,如下:

    <insert id="insertBatch" parameterType="list">
        INSERT INTO t_user (id,name,age) VALUES
        <foreach collection="collection" separator="," item="item">
            (#{item.id}, #{item.name}, #{item.age})
        </foreach>
    </insert>
    

    测试用例

    @Test
    public void insertBatch() throws IOException {
        try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            List<UserModel> userModelList = new ArrayList<>();
            for (int i = 0; i < 3; i++) {
                userModelList.add(UserModel.builder().id(10 + i).name("mybatis-" + i).age(20 + i).build());
            }
            int count = mapper.insertBatch(userModelList);
            log.info("{}", count);
        }
    }
    

    传入了3个用户信息,运行输出

    39:52.241 [main] DEBUG c.j.c.d.m.UserMapper.insertBatch - ==>  Preparing: INSERT INTO t_user (id,name,age) VALUES (?, ?, ?) , (?, ?, ?) , (?, ?, ?) 
    39:52.317 [main] DEBUG c.j.c.d.m.UserMapper.insertBatch - ==> Parameters: 10(Integer), mybatis-0(String), 20(Integer), 11(Integer), mybatis-1(String), 21(Integer), 12(Integer), mybatis-2(String), 22(Integer)
    39:52.327 [main] DEBUG c.j.c.d.m.UserMapper.insertBatch - <==    Updates: 3
    39:52.327 [main] INFO  c.j.chat05.demo8.Demo8Test - 3
    

    2.7 sql/include 元素

    这两个元素一般进行配合使用,可以实现代码重用的效果。

    sql 元素可以用来定义一段动态sql ,语法如下:

    <sql id="sql片段id">
    	各种动态sql
    </sql>
    

    其他地方需要使用的时候需要通过include 关键字进行引入:

    注意refid 值的写法:
    refid的值为mapper xml 的namespace 的值.sql_id,如果在同一个mapper 中,namespace 可以省略,直接写对应的sql_id 就可以了,如:

    <include refid="findSql"/>
    <include refid="com.javacode2018.chat05.demo8.mapper.UserMapper.findSql"/>
    

    案例:

    下面定义2 个查询,他们的查询条件一样,最后将条件抽出来用sql 元素定义了一个片段,然后进行共用。

    <sql id="findSql">
        <where>
            <if test="id!=null">
                AND id = #{id}
            </if>
            <if test="name!=null and name.toString()!=''">
                AND name = #{name}
            </if>
            <if test="age!=null">
                AND age = #{age}
            </if>
            <if test="idList!=null and idList.size()>=1">
                <foreach collection="idList" item="id" open="AND id in (" separator="," close=")">
                    #{id}
                </foreach>
            </if>
        </where>
    </sql>
    
    <select id="getList1" resultType="com.javacode2018.chat05.demo8.model.UserModel" parameterType="map">
        SELECT id,name,age FROM t_user
        <include refid="com.javacode2018.chat05.demo8.mapper.UserMapper.findSql" />
    </select>
    
    <select id="getList1Count" resultType="com.javacode2018.chat05.demo8.model.UserModel" parameterType="map">
        SELECT count(*) FROM t_user
        <include refid="findSql" />
    </select>
    

    2.8 bind元素

    bind 元素允许我们通过ognl 表达式在上下文中自定义一个变量,最后在动态sql 中可以使用这个变量。

    语法:

    <bind name="变量名称" value="ognl表达式">
    

    案例:

    对sql、include 中的案例进行扩展,添加一个按照用户名模糊查询,用户名在map 中对应的key 为likeName,主要修改上面sql 片段部分,在sql 中加入下面部分:

    <if test="likeName!=null and likeName.trim()!=''">
      <bind name="nameLike" value="'%'+likeName.trim()+'%'" />
      AND name like #{nameLike}
    </if>
    

    先判断传入的参数likeName是否不为空字符串,然后使用bind元素创建了一个变量nameLike,值为’%’+likeName.trim()+’%’。

    对应的测试用例:

    @Test
    public void getModelList() throws IOException {
        try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            Map<String, Object> paramMap = new HashMap<>();
            paramMap.put("likeName","java");
            List<UserModel> userModelList = mapper.getList1(paramMap);
            log.info("{}", userModelList);
        }
    }
    

    运行输出:

    06:25.633 [main] DEBUG c.j.c.d.mapper.UserMapper.getList1 - ==>  Preparing: SELECT id,name,age FROM t_user WHERE name like ? 
    06:25.671 [main] DEBUG c.j.c.d.mapper.UserMapper.getList1 - ==> Parameters: %java%(String)
    06:25.690 [main] DEBUG c.j.c.d.mapper.UserMapper.getList1 - <==      Total: 1
    06:25.691 [main] INFO  c.j.chat05.demo8.Demo8Test - [UserModel(id=1, name=路人甲Java, age=31)]
    

    注意输出中的第二部分,参数的值为%java%。

    三、# 和$

    3.1 区别

    3.1.1 处理方式

    对于#,mybatis 使用的是预编译,在处理#{}时,会将sql 中的#{} 替换为? 号,调用PreparedStatement 的set 方法来赋值。
    对于$,mybatis 不会修改或者转义字符,直接输出变量值

    3.1.2 参数是字符串

    #会对传入的字符数据加一个双引号​。
    $将传入的数据直接显示生成在sql 中​,适合于动态排序(动态字段)

    order by ${value} asc
    

    3.1.1 参数含义

    #{任意值}​,{ }中的值只是一个变量名,并无特殊含义。
    ${value} ,其中的标识符只能是value​,即将要传入sql 的值。

    3.1.1 防止Sql 注入

    #方式能够很大程度防止Sql 注入​。

    $方式无法防止Sql 注入​。

    3.2 ${} 的用法

    #{} 的用法上面已经有很多案例了,此处我们来一个${} 的案例。

    下面通过orderSql 变量传入任意的排序sql,如下:

    <select id="getList1" resultType="com.javacode2018.chat05.demo8.model.UserModel" parameterType="map">
        SELECT id,name,age FROM t_user
        <if test="orderSql">
            ${orderSql}
        </if>
    </select>
    

    传入值:

    orderSql = "order by id asc,age desc"
    

    最后运行产生的sql 如下:

    20:32.138 [main] DEBUG c.j.c.d.mapper.UserMapper.getList1 - ==>  Preparing: SELECT id,name,age FROM t_user order by id asc,age desc 
    20:32.173 [main] DEBUG c.j.c.d.mapper.UserMapper.getList1 - ==> Parameters: 
    20:32.196 [main] DEBUG c.j.c.d.mapper.UserMapper.getList1 - <==      Total: 6
    20:32.197 [main] INFO  c.j.chat05.demo8.Demo8Test - [UserModel(id=1, name=路人甲Java, age=31), UserModel(id=2, name=张学友, age=50), UserModel(id=3, name=刘德华, age=50), UserModel(id=10, name=mybatis-0, age=20), UserModel(id=11, name=mybatis-1, age=21), UserModel(id=12, name=mybatis-2, age=22)]
    

    mybatis 会对$ 包含部分直接进行sql 替换。

    至此,本文结束。我是陈冰安,一个Java学习者。欢迎关注我的公众号【暗星涌动】,愿与你一同进步。

    展开全文
  • 本文通过实例代码给大家介绍了MyBatis动态SQL标签用法,非常不错,具有参考借鉴价值,需要的朋友参考下吧
  • 主要介绍了Mybatis之动态sql标签的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • mybatis动态sql标签

    2019-03-12 15:47:11
    mybatis动态sql标签if标签where标签sql片段标签foreach标签trim标签背景1、prefix属性:在trim开始部分添加内容2、suffix属性:在trim结束部分添加内容3.prefixOverrides属性:去除trim开始部分的内容4、...

    if标签

    比如UserMapper.xml

    <!-- 根据条件查询用户 -->
    <select id="queryUserByWhere" parameterType="user" resultType="user">
    	SELECT id, username, birthday, sex, address FROM `user`
    	WHERE 1=1
    	<if test="sex != null and sex != ''">
    		AND sex = #{sex}
    	</if>
    	<if test="username != null and username != ''">
    		AND username LIKE
    		'%${username}%'
    	</if>
    </select>
    

    where标签

    比如UserMapper.xml

    <!-- 根据条件查询用户 -->
    <select id="queryUserByWhere" parameterType="user" resultType="user">
    	SELECT id, username, birthday, sex, address FROM `user`
    <!-- where标签可以自动添加where,同时处理sql语句中第一个and关键字 -->
    	<where>
    		<if test="sex != null">
    			AND sex = #{sex}
    		</if>
    		<if test="username != null and username != ''">
    			AND username LIKE
    			'%${username}%'
    		</if>
    	</where>
    </select>
    

    sql片段标签

    Sql中可将重复的sql提取出来,使用时用include引用即可,最终达到sql重用的目的。

    <!-- 根据条件查询用户 -->
    <select id="queryUserByWhere" parameterType="user" resultType="user">
    	<!-- SELECT id, username, birthday, sex, address FROM `user` -->
    	<!-- 使用include标签加载sql片段;refid是sql片段id -->
    	SELECT <include refid="userFields" /> FROM `user`
    	<!-- where标签可以自动添加where关键字,同时处理sql语句中第一个and关键字 -->
    	<where>
    		<if test="sex != null">
    			AND sex = #{sex}
    		</if>
    		<if test="username != null and username != ''">
    			AND username LIKE
    			'%${username}%'
    		</if>
    	</where>
    </select>
    
    <!-- 声明sql片段 -->
    <sql id="userFields">
    	id, username, birthday, sex, address
    </sql>
    

    如果要使用别的Mapper.xml配置的sql片段,可以在refid前面加上对应的Mapper.xml的namespace
    在这里插入图片描述

    foreach标签

    向sql传递数组或List,mybatis使用foreach解析
    比如根据多个id查询用户信息

    <!-- 根据ids查询用户 -->
    <select id="queryUserByIds" parameterType="queryVo" resultType="user">
    	SELECT * FROM `user`
    	<where>
    		<!-- foreach标签,进行遍历 -->
    		<!-- collection:遍历的集合,这里是QueryVo的ids属性 -->
    		<!-- item:遍历的项目,可以随便写,,但是和后面的#{}里面要一致 -->
    		<!-- open:在前面添加的sql片段 -->
    		<!-- close:在结尾处添加的sql片段 -->
    		<!-- separator:指定遍历的元素之间使用的分隔符 -->
    		<foreach collection="ids" item="item" open="id IN (" close=")"
    			separator=",">
    			#{item}
    		</foreach>
    	</where>
    </select>
    

    QueryVo
    在这里插入图片描述

    trim标签

    背景

    parameterType参数类型student是别名,里面的字段有id,name,age,sex被封装成bean对象,跟数据库中student表中字段一一对应,以下案例只为一个SQL语句。

    1、prefix属性:在trim开始部分添加内容

    例,在trim前面加上set

    <update id="updateStudent2" parameterType="student"> 
    	update student 
    	<trim prefix="set">
    		<if test="name!=null and name!=''">name=#{name},</if>
    		<if test="age!=null and age!=''">age=#{age},</if>
    		<if test="sex!=null and age!=''">sex=#{sex}</if>
    	</trim>
    	<where>id=#{id}</where>
    </update>
    

    2、suffix属性:在trim结束部分添加内容

    例,在后面添加上where内容

    <update id="updateStudent2" parameterType="student"> 
    	update student set 
    	<trim suffix="where id=#{id}">
    		<if test="name!=null and name!=''">name=#{name},</if>
    		<if test="age!=null and age!=''">age=#{age},</if>
    		<if test="sex!=null and age!=''">sex=#{sex}</if>
    	</trim>
    </update>
    

    3.prefixOverrides属性:去除trim开始部分的内容

    例,删掉name前面的set

    <update id="updateStudent2" parameterType="student"> 
    	update student set 
    	<trim prefixOverrides="set">
    		<if test="name!=null and name!=''">set name=#{name},</if>
    		<if test="age!=null and age!=''">age=#{age},</if>
    		<if test="sex!=null and age!=''">sex=#{sex}</if>
    	</trim>
    	<where>id=#{id}</where>
    </update>
    

    4、suffixOverrides属性:去除trim结束部分的内容

    例,删掉最后一个逗号

    <update id="updateStudent2" parameterType="student"> 
    	update student set 
    	<trim suffixOverrides=",">
    		<if test="name!=null and name!=''">name=#{name},</if>
    		<if test="age!=null and age!=''">age=#{age},</if>
    		<if test="sex!=null and age!=''">sex=#{sex},</if>
    	</trim>
    	<where>id=#{id}</where>
    </update>
    

    choose标签

    choose标签是按顺序判断其内部when标签中的test条件出否成立,如果有一个成立,则 choose 结束。当 choose 中所有 when 的条件都不满足时,则执行 otherwise 中的sql。类似于Java 的 switch 语句,choose 为 switch,when 为 case,otherwise 则为 default。
    例如下面例子,同样把所有可以限制的条件都写上,方面使用。choose会从上到下选择一个when标签的test为true的sql执行。安全考虑,我们使用where将choose包起来,放置关键字多于错误。

    <!--  choose(判断参数) - 按顺序将实体类 User 第一个不为空的属性作为:where条件 -->  
    <select id="getUserList_choose" resultMap="resultMap_user" parameterType="com.yiibai.pojo.User">  
        SELECT *  
          FROM User u   
        <where>  
            <choose>  
                <when test="username !=null ">  
                    u.username LIKE CONCAT(CONCAT('%', #{username, jdbcType=VARCHAR}),'%')  
                </when >  
                <when test="sex != null and sex != '' ">  
                    AND u.sex = #{sex, jdbcType=INTEGER}  
                </when >  
                <when test="birthday != null ">  
                    AND u.birthday = #{birthday, jdbcType=DATE}  
                </when >  
                <otherwise>  
                </otherwise>  
            </choose>  
        </where>    
    </select>
    

    choose (when,otherwize) ,相当于java 语言中的 switch ,与 jstl 中 的 choose 很类似

    selectKey标签

    在insert语句中,在Oracle经常使用序列、在MySQL中使用函数来自动生成插入表的主键,而且需要方法能返回这个生成主键。使用myBatis的selectKey标签可以实现这个效果。
    比如使用mysql的 LAST_INSERT_ID()函数

    <!-- 保存用户 -->
    <insert id="saveUser" parameterType="cn.itcast.mybatis.pojo.User">
    	<!-- selectKey 标签实现主键返回 -->
    	<!-- keyColumn:主键对应的表中的哪一列 -->
    	<!-- keyProperty:主键对应的pojo中的哪一个属性 -->
    	<!-- order:设置在执行insert语句前执行查询id的sql,还是在执行insert语句之后执行查询id的sql -->
    	<!-- resultType:设置返回的id的类型 -->
    	<selectKey keyColumn="id" keyProperty="id" order="AFTER"
    		resultType="int">
    		SELECT LAST_INSERT_ID()
    	</selectKey>
    	INSERT INTO `user`
    	(username,birthday,sex,address) VALUES
    	(#{username},#{birthday},#{sex},#{address})
    </insert>
    

    如果报错:必须为selectKey声明属性keyColumn;则去掉keyColumn属性即可

    set标签

    使用set标签可以将动态的配置SET 关键字,和剔除追加到条件末尾的任何不相关的逗号。

    <update id="updateUserById" parameterType="cn.itcast.mybatisdemo.pojo.User">  
        UPDATE user 
        <set>  
            <if test="username!= null and username!= '' ">  
               username = #{username },  
            </if>  
            <if test="sex!= null and sex!= '' ">  
                sex = #{sex},  
            </if>  
            <if test="birthday!= null ">  
                birthday = #{birthday},  
            </if>  
            <if test="address!= null ">  
                address= #{address},  
            </if>  
        </set>  
        WHERE id = #{id};      
    </update>  
    
    展开全文
  • MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架,MyBatis越来越受大家的喜爱了。下面给大家分享MyBatis使用动态SQL标签的小陷阱,感兴趣的朋友一起看看吧
  • 一步一步学完MyBatis的动态sql标签

    千次阅读 多人点赞 2020-06-03 23:21:20
    图文并茂+例子解析,全面理解MyBatis的动态sql标签
  • mybatis常用的动态sql标签

    千次阅读 2020-08-14 16:30:14
    而mybatis动态sql标签,正好可以解决这个烦人的问题。 mybatis常用的动态sql标签主要有以下几种: 标签 作用 if 单条件分支,相当于判断语句 choose、when、otherwise 多条件分支,相当于Java中的switch...
  • Mybatis的动态sql标签

    2017-07-05 17:04:02
    常用动态SQL标签有:if、where、foreach; If标签:作为判断入参来使用的,如果符合条件,则把if标签体内的SQL拼接上。 注意:用if进行判断是否为空时,不仅要判断null,也要判断空字符串‘’; Where标签:会去掉...
  • // TODO mybatis动态SQL标签详解
  • 动态SQL标签产生背景 MyBatis的强大特性之便是它的动态 SQL 。使用过 JDBC或其他类似框架的人都会知道,根据不同条件拼接 SQL 语句时不仅不能忘了必要的空格,还要注意省略掉列名列表最后的逗号,处理方式麻烦且...
  • 动态sql标签trim的用法

    万次阅读 2017-07-12 21:33:56
    在实际的项目需求中,有很多字段数值为空,这时需要我们采取有效的方式避免空值插入数据库,今天主要讲解一下动态sql标签trim的用法 2.实现步骤 实际需求:插入一条用户信息,空值不允许插入 1>取消指定的后缀 ①...
  • mybatis的动态sql标签

    2017-05-16 09:46:10
    mybatis的动态sql 标签 1. 拼接的sql 2. and ... and ... 说明:where标签在最后会将第一个条件的"and"给去掉,以防止sql拼写异常 3. ..., ..., 说明:set标签在最后会将最后一...
  • mybatis动态SQL标签的用法 动态 SQL MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其他类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句有多么痛苦。拼接的时候要确保不能忘了...
  • Mybatis入门之动态sql标签for,where和foreach for,where 有些时候我们可能需要实现根据用户输入的价格的最高价格,最低价格排序 这个时候那么就可以使用sql动态标签,减去多余的代码,给我们带来方便 话不多说,上...
  • 常用动态SQL标签: if where set foreach trim 1.1 if标签:XXX 功能:判断; <mapper namespace="com.cy.pj.Student"> <select id="findObjects" resultType="Student"> select * from student where 1...
  • mybatis 中动态 sql 标签的学习 在mybatis中,进行数据库操作时,不仅仅根据单一的标准来进行的增删改查,有时候,可能需要根据一个复杂的条件来操作,比如:根据一个用户的部分信息,查找一个用户;根据一个用户的...
  • 动态SQL标签大全

    2020-05-18 19:31:27
    目录动态SQL符号if标签(逻辑判断)where标签(SQL判断)choose,when,otherwise(Java中的switch)set (sql修改)trim(截断 添加)bind(模糊查询)foreach(循环)sql (复用) 动态SQL 根据不同的条件执行不同的SQL命令,...
  • mybatis的常用动态sql标签

    万次阅读 多人点赞 2019-03-24 17:29:17
    定义 sql 语句 select 标签 属性介绍: id :唯一的标识符. parameterType:传给此语句的参数的全路径名或别名 例:com.test.poso.User 或 user resultType :语句返回值类型或别名。注意,如果是集合,那么这里填写的...
  • 一、动态sql标签作用 动态SQL标签是Mybatis的一大特色,通过使用动态SQL标签可以完成一些稍微复杂的操作和简化开发。 动态SQL标签主要包括:if、where、set、trim、choose-when-otherwise、foreach,下面将对每个...
  • MyBatis学习之动态SQL标签

    千次阅读 2016-12-28 22:32:55
    在实际开发中,往往有一些复杂的SQL语句,MyBatis中就需要写一些动态的SQL语句,这时就需要借助于MyBatis中的OGNL表达式,这样可以很方便的实现一些复杂的逻辑,MyBatis中的动态SQL标签主要有以下几种: 1.if标签...
  • MyBatis动态SQL MyBatis通过 OGNL 来进行动态 SQL 的使用的。 对象导航图语言(Object Graph Navigation Language),简称OGNL,是应用于Java中的一个开源的表达式语言(Expression Language),它被集成在Struts2...
  • 学会了使用Mapper接口查询数据之后,我们再来学习一下Mybatis的动态sql标签,它是用来更灵活更精确的拼接sql语句用的 1.if标签 了解if标签之前我们先在UserMapper接口中创建一个方法SelectTest(User u),它的功能是...
  • Mybatis的动态SQL标签

    2020-08-19 09:02:22
    if标签 foreach标签 sql标签
  • mybatis动态SQL标签的用法 动态 SQL MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其他类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句有多么痛苦。拼接的时候要确保不能忘了必要...
  • iBatis动态SQL标签用法

    2012-09-07 11:14:03
    iBatis动态SQL标签用法   1、动态SQL片段 通过SQL片段达到代码复用  &lt;!-- 动态条件分页查询 --&gt;   &lt;sql id="sql_count"&gt;   select count(*)   &lt;/sql&...
  • Mybatis之动态sql标签

    万次阅读 多人点赞 2018-03-24 18:08:45
    1.Mybatis动态sql MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦。例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,424
精华内容 1,769
关键字:

动态sql标签