NO.07 MyBatis之动态Sql语句

目录

1、前言

2、 动态Sql之if标签

3、 动态Sql之where标签

4、 动态Sql之trim标签

 5、动态Sql之choose标签、when标签、otherwise标签

6、 动态Sql之foreach标签

6.1 使用foreach遍历array数组

6.2 使用foreach遍历List集合

6.3 使用foreach遍历Map集合

7、动态Sql之Sql片段

8、测试方法


1、前言

Mybatis框架的动态SQL技术是一种根据特定条件动态拼装SQL语句的功能,主要用于多条件查询,它存在的意义是为了解决拼接SQL语句字符串时的痛点问题。

本篇中使用的相关表和实体类参考:

NO.06 自定义映射resultMap_qq_46053741的博客-CSDN博客

2、 动态Sql之if标签

if标签通过test属性的表达式进行判断,若表达式的结果为true,则标签中的内容会执行;反之标签中的内容不会执行。下面以查询人员信息为例:

在MinisterMapper接口中声明getMinisterByConditionIf(@Param("age") Integer age,@Param("gender") String gender,@Param("ministerDutie") Integer ministerDutie)方法,因为是一个或者多个条件查询,返回的查询结果无法确认,因此方法的返回类型为List集合,集合中存储Minister类型的数据。 

    //使用if标签查找人员信息
    List<Minister> getMinisterByConditionIf(@Param("age") Integer age,@Param("gender") String gender,@Param("ministerDutie") Integer ministerDutie);

在映射文件中实现Sql语句,通过if标签拼接条件语句。

    <resultMap id="MinisterByCondition" type="Minister">
        <id property="id" column="id"></id>
        <result property="ministerName" column="minister_name"></result>
        <result property="age" column="age"></result>
        <result property="gender" column="gender"></result>
        <result property="ministerDutie" column="minister_dutie"></result>
        <association property="dutie" javaType="Dutie">
            <id property="dutieId" column="dutie_id"></id>
            <result property="dutieName" column="dutie_name"></result>
        </association>
    </resultMap>

<!--    List<Minister> getMinisterByConditionIf(@Param("age") Integer age,@Param("gender") String gender,@Param("ministerDutie") Integer ministerDutie);-->
    <select id="getMinisterByConditionIf" resultMap="MinisterByCondition">
        select *from t_minister where 1=1
        <if test="age!='' and age!=null">
            and age=#{age}
        </if>
        <if test="gender!='' and gender!=null">
            and gender=#{gender}
        </if>
        <if test="ministerDutie!='' and ministerDutie!=null">
            and minister_dutie=#{ministerDutie}
        </if>
    </select>

 if标签中如果test的判断条件为true,则将if标签中的条件拼接到select *from t_minister where 1=1后面;如果为false,则进行下一个判断。select *from t_minister where 1=1语句中的1=1为了防止出现所有if标签不成立情况,造成Sql语句为select *from t_minister where出错。

3、 动态Sql之where标签

在【2】中提到在Sql的where条件判断后添加1=1为了防止出现所有if标签不成立情况,造成Sql语句为select *from t_minister where出错。下面引入where标签可以解决select *from t_minister where出错的问题。

where和if一般结合使用:

若where标签中的if条件都不满足,则where标签没有任何功能,即不会添加where关键字

若where标签中的if条件满足,则where标签会自动添加where关键字,并将条件最前方多余的 and去掉

注意:where标签不能去掉条件最后多余的and

因此在映射文件中的Sql语句可以表示成:

    <resultMap id="MinisterByCondition" type="Minister">
        <id property="id" column="id"></id>
        <result property="ministerName" column="minister_name"></result>
        <result property="age" column="age"></result>
        <result property="gender" column="gender"></result>
        <result property="ministerDutie" column="minister_dutie"></result>
        <association property="dutie" javaType="Dutie">
            <id property="dutieId" column="dutie_id"></id>
            <result property="dutieName" column="dutie_name"></result>
        </association>
    </resultMap>

<!--    List<Minister> getMinisterByConditionIf(@Param("age") Integer age,@Param("gender") String gender,@Param("ministerDutie") Integer ministerDutie);-->
    <select id="getMinisterByConditionIf" resultMap="MinisterByCondition">
        select *from t_minister
        <where>
            <if test="age!='' and age!=null">
                age=#{age} and
            </if>
            <if test="gender!='' and gender!=null">
                gender=#{gender} and
            </if>
            <if test="ministerDutie!='' and ministerDutie!=null">
                minister_dutie=#{ministerDutie}
            </if>
        </where>
    </select>

 从上述代码中可以发现新的问题,如果最后一个if条件判断为false,那么Sql语句会出现类似select *from t_minister where age=‘18’ and gender='男' and的错误,Sql语句最后面的and无法去除,要解决这个问题则需要配合trim标签。

4、 动态Sql之trim标签

trim用于去掉或添加标签中的内容,常用属性:

prefix:在trim标签中的内容的前面添加某些内容

prefixOverrides:在trim标签中的内容的前面去掉某些内容

suffix:在trim标签中的内容的后面添加某些内容

suffixOverrides:在trim标签中的内容的后面去掉某些内容

下面演示trim标签的使用,同样用于getMinisterByConditionIf(@Param("age") Integer age,@Param("gender") String gender,@Param("ministerDutie") Integer ministerDutie)方法。

    <resultMap id="MinisterByCondition" type="Minister">
        <id property="id" column="id"></id>
        <result property="ministerName" column="minister_name"></result>
        <result property="age" column="age"></result>
        <result property="gender" column="gender"></result>
        <result property="ministerDutie" column="minister_dutie"></result>
        <association property="dutie" javaType="Dutie">
            <id property="dutieId" column="dutie_id"></id>
            <result property="dutieName" column="dutie_name"></result>
        </association>
    </resultMap>

<!--    List<Minister> getMinisterByConditionIf(@Param("age") Integer age,@Param("gender") String gender,@Param("ministerDutie") Integer ministerDutie);-->
    <select id="getMinisterByConditionIf" resultMap="MinisterByCondition">
        select *from t_minister
        <where>
            <trim suffixOverrides="and">
                <if test="age!='' and age!=null">
                    age=#{age} and
                </if>
                <if test="gender!='' and gender!=null">
                    gender=#{gender} and
                </if>
                <if test="ministerDutie!='' and ministerDutie!=null">
                    minister_dutie=#{ministerDutie} and
                </if>
            </trim>
        </where>
    </select>

 5、动态Sql之choose标签、when标签、otherwise标签

choose、when、otherwise功能类似于if、else if、else。

下面演示上面三个标签的使用,用于getMinisterByConditionIf(@Param("age") Integer age,@Param("gender") String gender,@Param("ministerDutie") Integer ministerDutie)方法。

    <resultMap id="MinisterByCondition" type="Minister">
        <id property="id" column="id"></id>
        <result property="ministerName" column="minister_name"></result>
        <result property="age" column="age"></result>
        <result property="gender" column="gender"></result>
        <result property="ministerDutie" column="minister_dutie"></result>
        <association property="dutie" javaType="Dutie">
            <id property="dutieId" column="dutie_id"></id>
            <result property="dutieName" column="dutie_name"></result>
        </association>
    </resultMap>

<!--    List<Minister> getMinisterByConditionIf(@Param("age") Integer age,@Param("gender") String gender,@Param("ministerDutie") Integer ministerDutie);-->
    <select id="getMinisterByConditionIf" resultMap="MinisterByCondition">
        select *from t_minister
        <where>
            <choose>
                <when test="age!='' and age!=null">
                    age=#{age}
                </when>
                <when test="gender!='' and gender!=null">
                    gender=#{gender}
                </when>
                <when test="ministerDutie!='' and ministerDutie!=null">
                    minister_dutie=#{ministerDutie}
                </when>
            </choose>
        </where>
    </select>

上述代码中,当其中一个when判断为true时,后面的when不再进行判断。因此最终得到的Sql语句的where后面只用一个条件。

6、 动态Sql之foreach标签

Mybatis中foreach 标签用于循环语句,它很好的支持了数据和 List、Set 接口的集合,并对此提供遍历的功能。对于Sql 语句中含有 in、or 条件等,需要迭代条件集合来生成条件的情况,使用 foreach标签实现 Sql 条件的迭代。

foreach 标签中各个属性作用:

  • item:设置用于迭代集合中每个元素的变量。
  • index:指定一个名字,表示在迭代过程中每次迭代到的位置(在Map集合中指定Map的键)。
  • open:表示条件以什么开始(例:in条件语句,使用“(”开始)。
  • separator:表示在每次进行迭代之间以什么符号作为分隔符(例:or条件语句,使用“or”开始作为分隔符)。
  • close:表示该语句以什么结束(例:in条件语句,使用“)”开始)。
  • collection 属性在不同情况下该属性的值是不一样的,主要有以下 3 种情况:
  1. 如果传入的是单参数且参数类型是一个 List,collection 属性值为 list。
  2. 如果传入的是单参数且参数类型是一个 array 数组,collection 的属性值为 array。
  3. 如果传入的参数是多个,需要把它们封装成一个 Map;单参数也可以封装成 Map。Map 的 key 是参数名,collection 属性值是传入的 List 或 array 对象在自己封装的 Map 中的 key。

6.1 使用foreach遍历array数组

在MinisterMapper接口中声明getMinisterById(int[] ministerIds)方法

    //根据id删除人员信息
    void deleteMinisterById(@Param("map") Map<String,Integer> ministerIds);

在映射文件中实现Sql语句,where标签中如果if条件判断为false,则Sql语句为select *from t_minister,将所有人员信息查找出来;如果if条件判断为true,则"id in"将会拼接到Sql语句中,再通过foreach遍历array数组,查询出id存在于数组array(例如:array={1,2,3,4})中的人员信息,此时的Sql语句为select *from t_minister where id in (1,2,3,4)。因为是单参数且参数类型为array数组,所以collection属性可以通过array为参数查找到ministerIds数组。

    <resultMap id="MinisterByCondition" type="Minister">
        <id property="id" column="id"></id>
        <result property="ministerName" column="minister_name"></result>
        <result property="age" column="age"></result>
        <result property="gender" column="gender"></result>
        <result property="ministerDutie" column="minister_dutie"></result>
        <association property="dutie" javaType="Dutie">
            <id property="dutieId" column="dutie_id"></id>
            <result property="dutieName" column="dutie_name"></result>
        </association>
    </resultMap>
<!--    List<Minister> getMinisterById(int[] ministerIds);-->
    <select id="getMinisterById" resultMap="MinisterByCondition">
        select *from t_minister
        <where>
            <if test="array!=null">
                id in
                <foreach collection="array" open="(" separator="," close=")" item="ids">
                    #{ids}
                </foreach>
            </if>
        </where>
    </select>

 注意:也可以通过@Param注解的方式获取数组参数。

6.2 使用foreach遍历List集合

在MinisterMapper接口中声明getMinisterByministerDutie(List<Integer> ministerDuties)方法,参数类型为List集合

    //根据ministerDutie查找符合条件的人员信息
    List<Minister> getMinisterByministerDutie(List<Integer> ministerDuties);

在映射文件中实现Sql语句,该Sql语句也是通过判断if标签中的条件来决定Sql语句拼接。

因为是单参数且参数类型为List集合,所以collection属性可以通过list为参数查找到ministerIds集合。

    <resultMap id="MinisterByCondition" type="Minister">
        <id property="id" column="id"></id>
        <result property="ministerName" column="minister_name"></result>
        <result property="age" column="age"></result>
        <result property="gender" column="gender"></result>
        <result property="ministerDutie" column="minister_dutie"></result>
        <association property="dutie" javaType="Dutie">
            <id property="dutieId" column="dutie_id"></id>
            <result property="dutieName" column="dutie_name"></result>
        </association>
    </resultMap>
<!--    List<Minister> getMinisterByministerDutie(List<Integer> ministerDuties);-->
    <select id="getMinisterByministerDutie" resultMap="MinisterByCondition">
        select *from t_minister
        <where>
            <if test="list!=null">
                id in (
                <foreach collection="list" separator="," item="ids">
                    #{ids}
                </foreach>
                )
            </if>
        </where>
    </select>

 注意:也可以通过@Param注解的方式获取数组参数。 

6.3 使用foreach遍历Map集合

在MinisterMapper接口中声明deleteMinisterById(@Param("map") Map<String,Integer> ministerIds)方法,参数类型为Map集合

    //根据id删除人员信息
    void deleteMinisterById(@Param("map") Map<String,Integer> ministerIds);

在映射文件中实现Sql语句,该Sql语句通过foreach标签拼接Sql语句。collection标签中的index属性设置为map的键,item属性设置为map的值。

<!--    void deleteMinisterById(Map<String,Integer> ministerIds);-->
    <delete id="deleteMinisterById">
        delete from t_minister where id in
        <foreach collection="map" index="key" item="value" separator="," open="(" close=")">
            #{value}
        </foreach>
    </delete>

7、动态Sql之Sql片段

sql片段,可以记录一段公共sql片段,在使用的地方通过include标签进行引入。

例如:查询所有人员信息

在MinisterMapper接口中声明 getAllMinister()方法。

    //查询所有人员信息
    List<Minister> getAllMinister();

在映射文件中实现Sql语句, sql标签中的id属性是该Sql片段的唯一标识,在select语句中使用include标签,refid属性设置引用Sql片段的id,通过refid属性的值查找到Sql片段,将Sql片段拼接到Sql语句中。Sql语句为:select id,minister_name ministerName,age,gender,minister_dutie ministerDutie from t_minister

    <sql id="SqlName">
        id,minister_name ministerName,age,gender,minister_dutie ministerDutie
    </sql>
<!--    List<Minister> getAllMinister();-->
    <select id="getAllMinister" resultType="Minister">
        select <include refid="SqlName"></include> from t_minister
    </select>

8、测试方法

@Test
    public void getMinisterByConditionIf() {
        SqlSession sqlSession= JdbcUtiles.getSqlSession();
        //创建MinisterMapper的代理实现类对象
        MinisterMapper ministerMapper=sqlSession.getMapper(MinisterMapper.class);
        List<Minister> list=ministerMapper.getMinisterByConditionIf(null,null,2);
        for(Minister minister:list){
            System.out.println(minister);
        }

        JdbcUtiles.closeSqlSession(sqlSession);
    }

    @Test
    public void getMinisterById() {
        SqlSession sqlSession= JdbcUtiles.getSqlSession();
        //创建MinisterMapper的代理实现类对象
        MinisterMapper ministerMapper=sqlSession.getMapper(MinisterMapper.class);
        int[] array={6,7,8};
        List<Minister> list=ministerMapper.getMinisterById(array);
        for(Minister minister:list){
            System.out.println(minister);
        }

        JdbcUtiles.closeSqlSession(sqlSession);
    }

    @Test
    public void getMinisterByministerDutie() {
        SqlSession sqlSession= JdbcUtiles.getSqlSession();
        //创建MinisterMapper的代理实现类对象
        MinisterMapper ministerMapper=sqlSession.getMapper(MinisterMapper.class);
        List<Integer> list1=new ArrayList<Integer>();
        list1.add(1);
        list1.add(2);
        list1.add(3);
        List<Minister> list=ministerMapper.getMinisterByministerDutie(list1);
        for(Minister minister:list){
            System.out.println(minister);
        }

        JdbcUtiles.closeSqlSession(sqlSession);
    }
    @Test
    public void deleteMinisterById() {
        SqlSession sqlSession= JdbcUtiles.getSqlSession();
        //创建MinisterMapper的代理实现类对象
        MinisterMapper ministerMapper=sqlSession.getMapper(MinisterMapper.class);
        Map<String,Integer> map=new HashMap<String, Integer>();
        map.put("赵高",9);
        map.put("秦宣",10);

        ministerMapper.deleteMinisterById(map);

        JdbcUtiles.closeSqlSession(sqlSession);
    }
    @Test
    public void getAllMinister() {
        SqlSession sqlSession= JdbcUtiles.getSqlSession();
        //创建MinisterMapper的代理实现类对象
        MinisterMapper ministerMapper=sqlSession.getMapper(MinisterMapper.class);
        List<Minister> list=ministerMapper.getAllMinister();
        for(Minister minister:list){
            System.out.println(minister);
        }

        JdbcUtiles.closeSqlSession(sqlSession);
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值