Mybatis中的动态sql

1.Mybatis动态sql介绍

​ 在传统的JDBC连接数据库总,我们需要编写大量的java代码来对sql语句进行拼接,对sql语句的拼接使得代码的可复用性很差,我们将大量的时间花在了编写java拼接sql语句上,开发速度慢。Mybatis使用了动态sql语句的方法,使得拼接sql代码的时间大大减少,引用Mybatis官方的就是:动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦 。

2.Mybatis动态sql的使用

2.1 Mybatis简介

使用动态 SQL 并非一件易事,但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显著地提升了这一特性的易用性。

如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。

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

2.2 万能的Map

在介绍动态sql之前,我们需要了解的是,在进行数据库中进行数据操作时,引入Map可以达到很多的操作。下面我们简单介绍一下的Map的强大。

代码:

UserMapper接口

package com.xiaoli.dao;

import com.xiaoli.pojo.User;

import java.util.List;
import java.util.Map;

public interface UserMapper {

    //查询用户:万能的Map
    //我们需要查询id为1的用户,不使用基本数据类型进行查询,使用Map
    List<User> getUserList(Map map);
}

UserMapper.xml配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.xiaoli.dao.UserMapper">

    <!--
        parameterType:表示传入的元素类型

        select * from user where id = #{user_id}
        1.表示传入的元素user_id
        2.理解为map映射的key为:"user_id",然后取key为user_id的值value
    -->
    <select id="getUserList" parameterType="map" resultType="user">
        select * from user where id = #{user_id}
    </select>
</mapper>

测试代码:

package com.xiaoli.dao;

import com.xiaoli.pojo.User;
import com.xiaoli.util.MybatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class TestUserMapper {

    @Test
    public void testGetUserList(){

        SqlSession sqlSession = MybatisUtil.getSqlSession();

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

        Map<String,Object> map = new HashMap<String,Object>();
        //传入key为user_id,value值为1的数据
        map.put("user_id",1);

        List<User> userList = mapper.getUserList(map);

        for (User user : userList) {
            System.out.println(user);
        }

        sqlSession.close();
    }
}

测试结果:

image-20210414110904703

2.3 if元素

  1. if元素语法(举例)

     <select id="getUserIf" parameterType="map" resultType="User">
            select * from user where 1 = 1
            <if test="user_id != null">
                and id = #{user_id}
            </if>
        </select>
    
  2. 代码测试

    • UserMapper接口

      package com.xiaoli.dao;
      
      import com.xiaoli.pojo.User;
      
      import java.util.List;
      import java.util.Map;
      
      public interface UserMapper {
      
          //动态sql:if元素
          List<User> getUserIf(Map map);
      }
      
      
    • UserMapper.xml配置文件

      <?xml version="1.0" encoding="UTF-8" ?>
      <!DOCTYPE mapper
              PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
              "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
      
      <mapper namespace="com.xiaoli.dao.UserMapper">
          
          <!--动态sql:if元素-->
          <select id="getUserIf" parameterType="map" resultType="User">
              select * from user where 1 = 1
              <if test="user_id != null">
                  and id = #{user_id}
              </if>
          </select>
      </mapper>
      
    • 测试代码

      package com.xiaoli.dao;
      
      import com.xiaoli.pojo.User;
      import com.xiaoli.util.MybatisUtil;
      import org.apache.ibatis.session.SqlSession;
      import org.junit.Test;
      
      import java.util.HashMap;
      import java.util.List;
      import java.util.Map;
      
      public class TestUserMapper {
          //动态sql:if元素
          @Test
          public void testGetUserIf(){
      
              SqlSession sqlSession = MybatisUtil.getSqlSession();
      
              UserMapper mapper = sqlSession.getMapper(UserMapper.class);
      
              Map<String,Object> map = new HashMap<String,Object>();
              //传入key为user_id,value值为1的数据
              map.put("user_id",1);
      
              List<User> userList = mapper.getUserIf(map);
      
              for (User user : userList) {
                  System.out.println(user);
              }
      
              sqlSession.close();
          }
      }
      
      
    • 测试结果:

      image-20210414112154341

2.4 where元素

细心的你可能发现了,上面使用的if元素存在一个局限性,在外面查询时,需要在条件查询前加上where 1=1 条件,这样我们才能在后面的使用if元素,所以Mybatis官方为我们引入了where元素。

代码测试:

  • UserMapper接口

    package com.xiaoli.dao;
    
    import com.xiaoli.pojo.User;
    
    import java.util.List;
    import java.util.Map;
    
    public interface UserMapper {
        //动态sql:where元素
        List<User> getUserWhere(Map map);
    }
    
    
  • UserMapper.xml配置文件

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="com.xiaoli.dao.UserMapper">
    
        <!--动态sql:where元素-->
        <select id="getUserWhere" parameterType="map" resultType="User">
            select * from user
            <where>
                <if test="user_id != null">
                    id = #{user_id}
                </if>
            </where>
    
        </select>
    </mapper>
    
  • 测试代码

    package com.xiaoli.dao;
    
    import com.xiaoli.pojo.User;
    import com.xiaoli.util.MybatisUtil;
    import org.apache.ibatis.session.SqlSession;
    import org.junit.Test;
    
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    public class TestUserMapper {    
        //动态sql:where元素
        @Test
        public void testGetUserWhere(){
    
            SqlSession sqlSession = MybatisUtil.getSqlSession();
    
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    
            Map<String,Object> map = new HashMap<String,Object>();
            //传入key为user_id,value值为1的数据
            map.put("user_id",1);
    
            List<User> userList = mapper.getUserIf(map);
    
            for (User user : userList) {
                System.out.println(user);
            }
    
            sqlSession.close();
        }
    
    }
    
    
  • 测试结果

    image-20210414113332099

2.5 chose(where,otherwise)元素

chose(where,otherwise)解决了一个问题,当我们不想使用所有的元素时,我们需要一种能够选择的方式来执行sq语句,我们选择使用chose和其附带的元素,当我们需要在sql语句中做选择,我们可以使用他。引用官方的介绍就是:

“有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。”

  • 代码测试:

    UserMapper接口

    package com.xiaoli.dao;
    
    import com.xiaoli.pojo.User;
    
    import java.util.List;
    import java.util.Map;
    
    public interface UserMapper {
    
        //动态sql:chose(when,otherwise)元素
        List<User> getUserChoseWhenOtherwise(Map map);
    }
    
    

    UserMapper.xml配置文件

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="com.xiaoli.dao.UserMapper">
        <!--动态sql:chose(when,otherwise)元素-->
        <select id="getUserChoseWhenOtherwise" parameterType="map" resultType="User">
            select * from user
            <where>
                <choose>
                    <when test="stu_id != null">
                        id = #{stu_id}
                    </when>
                    <when test="stu_name != null">
                        and name = #{stu_name}
                    </when>
                    <otherwise>
                        and id = 1
                    </otherwise>
                </choose>
            </where>
        </select>
    </mapper>
    
  • 测试代码:

    package com.xiaoli.dao;
    
    import com.xiaoli.pojo.User;
    import com.xiaoli.util.MybatisUtil;
    import org.apache.ibatis.session.SqlSession;
    import org.junit.Test;
    
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    public class TestUserMapper {
        //动态sql:chose(when,otherwise)元素
        @Test
        public void testGetUserChoseWhenOtherwise(){
            SqlSession sqlSession = MybatisUtil.getSqlSession();
    
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    
            Map map = new HashMap<String,Object>();//我们这里尝试不向map中传入数据,查看查询到的数据
    
            List<User> userChoseWhenOtherwise = mapper.getUserChoseWhenOtherwise(map);
    
            for (User user : userChoseWhenOtherwise) {
                System.out.println(user);
            }
    
            sqlSession.close();
        }
    
    }
    
    

    测试结果:

    image-20210414190416173

  • 接下来我们尝试向Map中传入我们预先指定的参数,查看代码测试结果:

    测试代码:

    package com.xiaoli.dao;
    
    import com.xiaoli.pojo.User;
    import com.xiaoli.util.MybatisUtil;
    import org.apache.ibatis.session.SqlSession;
    import org.junit.Test;
    
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    public class TestUserMapper {
        //动态sql:chose(when,otherwise)元素
        @Test
        public void testGetUserChoseWhenOtherwise(){
            SqlSession sqlSession = MybatisUtil.getSqlSession();
    
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    
            Map map = new HashMap<String,Object>();
    
            //我们向map中传入我们预先指定的元素,查看数据的查询结果
            map.put("stu_id",2);
    
            List<User> userChoseWhenOtherwise = mapper.getUserChoseWhenOtherwise(map);
    
            for (User user : userChoseWhenOtherwise) {
                System.out.println(user);
            }
    
            sqlSession.close();
        }
    
    }
    
    

    测试结果:

    image-20210414190947590

2.6 where,set元素

在CRUD的修改中,我们需要用到where与set元素的组合。

  • 代码测试:

    UserMapper接口

    package com.xiaoli.dao;
    
    import com.xiaoli.pojo.User;
    
    import java.util.List;
    import java.util.Map;
    
    public interface UserMapper {
        //动态sql:where,set元素
        int updateUserWhereSet(Map map);
    }
    
    

    UserMapper.xml配置文件

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="com.xiaoli.dao.UserMapper">
        <!--动态sql:where,set元素-->
        <update id="updateUserWhereSet" parameterType="map">
            update user
            <set>
                <if test="stu_name != null"> name = #{stu_name},</if>
                <if test="stu_password != null"> password = #{stu_password}</if>
            </set>
            <where>
                id = #{stu_id}
            </where>
        </update>
    </mapper>
    
    • 测试代码:

      package com.xiaoli.dao;
      
      import com.xiaoli.pojo.User;
      import com.xiaoli.util.MybatisUtil;
      import org.apache.ibatis.session.SqlSession;
      import org.junit.Test;
      
      import java.util.HashMap;
      import java.util.List;
      import java.util.Map;
      
      public class TestUserMapper {
      
          //动态sql:where,set元素
          @Test
          public void testUpdateUserWhereSet(){
              SqlSession sqlSession = MybatisUtil.getSqlSession();
      
              UserMapper mapper = sqlSession.getMapper(UserMapper.class);
      
              Map map = new HashMap<String,Object>();
              map.put("stu_id",1);//设置id
              map.put("stu_name","小扎");//设置需要修改的属性
      
              int i = mapper.updateUserWhereSet(map);
      
              System.out.println(i);
      
              sqlSession.commit();//设置事务提交
              sqlSession.close();
          }
      
      }
      
      

      测试结果:

      image-20210414192444325

      image-20210414192605082

2.7 foreach遍历元素

我们为什么引入foreach元素,动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。

你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。

  • 代码测试:

    UserMapper接口

    package com.xiaoli.dao;
    
    import com.xiaoli.pojo.User;
    
    import java.util.List;
    import java.util.Map;
    
    public interface UserMapper {
    
        //动态sql:foreach遍历元素
        List<User> getUserForEach(Map map);
    }
    
    

    UserMapper.xml配置文件

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="com.xiaoli.dao.UserMapper">
    
        <!--动态sql:foreach遍历元素-->
        <!--
            foreach标签:遍历集合或者容器
            index:起点
            collection:遍历的集合
            open与close:对foreach标签中的元素包围
            separator:分界符
        -->
        <select id="getUserForEach" parameterType="map" resultType="User">
            select * from user
            <where>
                <foreach collection="userList" index="0" item="this" open="(" close=")" separator="or">
                    id = #{this}
                </foreach>
            </where>
        </select>
    </mapper>
    
    • 测试代码

      package com.xiaoli.dao;
      
      import com.xiaoli.pojo.User;
      import com.xiaoli.util.MybatisUtil;
      import org.apache.ibatis.session.SqlSession;
      import org.junit.Test;
      
      import java.util.ArrayList;
      import java.util.HashMap;
      import java.util.List;
      import java.util.Map;
      
      public class TestUserMapper {s
          //动态sql:foreach遍历元素
          @Test
          public void testGetUserForEach(){
              SqlSession sqlSession = MybatisUtil.getSqlSession();
      
              UserMapper mapper = sqlSession.getMapper(UserMapper.class);
      
              Map map = new HashMap<String,Object>();
              List<Integer> list = new ArrayList<>();
              list.add(1);//我们先集合中放入三个元素
              list.add(2);
              list.add(4);
      
              map.put("userList",list);
      
              List<User> userForEach = mapper.getUserForEach(map);
      
              for (User forEach : userForEach) {
                  System.out.println(forEach);
              }
      
              sqlSession.close();
      
          }
      
      }
      
      

      测试结果:

      image-20210414200010789

3.sql片段

有时候可能某个 sql 语句我们用的特别多,为了增加代码的重用性,简化代码,我们需要将这些代码抽

取出来,然后使用时直接调用。

  • 抽取sql片段

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="com.xiaoli.dao.UserMapper">
       <sql id="sql_example">
            <where>
                id = #{id}
            </where>
        </sql>
    
        <!--抽取sql片段-->
        <select id="getUserSql" parameterType="_int" resultType="User">
            select * from user
            <include refid="sql_example"></include>
        </select>
    </mapper>
    
  • 测试代码:

    //动态sql:sql片段
        @Test
        public void testGetUserSql(){
            SqlSession sqlSession = MybatisUtil.getSqlSession();
    
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    
            List<User> userSql = mapper.getUserSql(1);
    
            for (User user : userSql) {
                System.out.println(user);
            }
            sqlSession.close();
        }
    

    测试结果:

    image-20210414204119466

posted on 2021-04-14 20:46  Code_xiaoli  阅读(113)  评论(0)    收藏  举报



Live2D