MyBatis之动态sql

Posted 简单点了

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MyBatis之动态sql相关的知识,希望对你有一定的参考价值。

MyBatis之动态sql

需要掌握动态SQL的使用的方法

3.动态sql

3.1常见的动态查询条件

  • if,就是判定
  • choose
  • where等价于sql中的where
  • set,灵活的去掉关键字
  • trim,设置更新语句
  • foreach,迭代形成一个集合

3.2if和where用于查询

1.案例

    <!--    selectStudent查询学生-->
    <resultMap id="testStudent" type="Student">
        <result column="id" property="id"/>
        <result column="name" property="student_name"/>
    </resultMap>
    //注意查询前面需要设置and不然的拼接sql的时候不能正确的执行
     <select id="selectStudent" resultMap="testStudent">
        select * from student
        <where>
            <if test="id!=null">
             and  id=#id
            </if>
            <if test="student_name!=null and student_name!=''">
                and    name like concat('%',#student_name,'%')
            </if>
            limit 0,1
        </where>
    </select>

接口

    Student selectStudent(@Param("id") Integer id,@Param("student_name")String name);

测试代码

    @Test
    public void selectStudentTest() 
        SqlSession sqlSession = null;
        int count = 0;
        try 
            sqlSession = MyBatisUtil.createSqlSession();
            Student student = sqlSession.getMapper(StudentMapper.class).selectStudent(null,"张");
            System.out.println("测试动态sql");
            System.out.println(student.toString());
         catch (Exception e) 
            e.printStackTrace();
         finally 
            MyBatisUtil.closeSqlSession(sqlSession);
        
    

3.3if和set用于修改

其实这个案例只是用来进行测试的,真正的案例中是不会使用set和if组合进行null判断的,因为在处理请求的时候就进行了判断,并且一般都是更新全部的数据而不是只更新部分的数据

解决更新的时候不会出现某个字段的为null的时候也把对应的字段更新了

数据库数据

类的代码

更新的sql

  • 注意每个的后面需要带上一个逗号

    <!--    动态的更新学生的信息-->
    <update id="updateStudent2" parameterType="cn.smbms.pojo.Student">
        update student
        <set>
            <if test="student_name!=null and student_name!=''">name=#student_name,</if>
            <if test="sex!=null and sex!=''">sex=#sex,</if>
        </set>
        where id=#id
    </update>

测试代码

  • 假设只更新名字不更新性别

 sqlSession = MyBatisUtil.createSqlSession();
           int line= sqlSession.getMapper(StudentMapper.class).updateStudent2(new Student(1,"张三",""));
            sqlSession.commit();
            System.out.println("影响的行数");
            System.out.println(line);

图 1 改变后的张的信息为张三

3.4if和trim类似if和set的用法

改造3.3中案例的sql代码

注意格式就可以

<!--    改造成if+trim的用法-->
    <update id="updateStudent2" parameterType="cn.smbms.pojo.Student">
        update student
        <trim prefix="set"  suffixOverrides="," suffix="where id=#id">
            <if test="student_name!=null and student_name!=''">name=#student_name,</if>
            <if test="sex!=null and sex!=''">sex=#sex,</if>
        </trim>

 </update>

图2 修改后的信息

3.5foreach完成复杂查询

  • 集合
  • 数组
  • map都可以进行处理

案例:查询多个id的学生的信息,传入的数据是一个数组

foreach常见的属性

  • item指定的是迭代的别名,比如我传入的是idx但是用的时候采用的是tid的形式
  • index,每次迭代的位置
  • open,表示从什么语句开始,比如in就是从(开始的
  • close,表示从什么结束,in就是)结束
  • separator,表示每次循环的时候采用的分隔符,比如说in就是逗号
  • collection指定的是传入数据的类型,采用的是数组的类型的话就是array,list就是集合
  • 如果传入的数据是多个参数的话可以采用map的形式

接口

    //查询的数据是一个集合
    List<Student> getIdsStudent(Integer[] idx);

sql代码

<!--  查询数组中的数据  -->
    <resultMap id="getIdsStudentMap" type="Student">
        <result property="id" column="id"/>
        <result property="student_name" column="name"/>
        <result property="sex" column="sex"/>
    </resultMap>
    <select id="getIdsStudent" resultMap="getIdsStudentMap">
        select  * from student where id in
    <foreach collection="array" item="tid" open="(" close=")" separator=",">
        #tid
    </foreach>
    </select>

测试代码

  • 查询id为1和2的信息

    @Test
    public void getIdsStudentTest() 
        SqlSession sqlSession = null;
        int count = 0;
        try 
            sqlSession = MyBatisUtil.createSqlSession();
            Integer idx[]=1,2;
            List<Student> students = sqlSession.getMapper(StudentMapper.class).getIdsStudent(idx);
            sqlSession.commit();
            System.out.println("查询指定指定id集合的数据");
            System.out.println(students.toString());
         catch (Exception e) 
            e.printStackTrace();
         finally 
            MyBatisUtil.closeSqlSession(sqlSession);
        
    

图3 查询多条数据

3.6传入list集合的形式

只需要将3.5案例中的array的格式变成list集合的形式就可以了

接口定义

 //查询的数据是一个集合
    List<Student> getIdsStudentList(List<Integer> idx);

sql定义

<!--    查询的数据是一个集合-->
    <select id="getIdsStudentList" resultMap="getIdsStudentMap">
        select  * from student where id in
        <foreach collection="list" item="tid" open="(" close=")" separator=",">
            #tid
        </foreach>
    </select>

测试代码

sqlSession = MyBatisUtil.createSqlSession();
            List<Integer> idx=new ArrayList();
            idx.add(2);
            idx.add(3);
            List<Student> students = sqlSession.getMapper(StudentMapper.class).getIdsStudentList(idx);
            sqlSession.commit();
            System.out.println("查询指定指定id的List集合的数据");
            System.out.println(students.toString());

图3 测试list

和array的区别在于把要传入的数据变成一个集合的形式就可以了

3.7传入map类型的形式

案例:想查询所有的指定学生性别和账号信息的所有的学生的信息

  • 传入的参数是一个map。
  • 第一个参数是sex,就是用来设置要查询的数据
  • 第二个参数是idx,指定符合指定性别和id的学生的信息

接口定义

    //查询的数据是一个map
    List<Student> getMapStudentList(Map<String,Object> map);

sql定义

  • collection中的值是map中的键的名称

<!--sql定义-->
<!--    idx是前面指定的key的值,但是里面保存的是集合-->
    <select id="getMapStudentList" resultMap="getIdsStudentMap">
        select  * from student where sex=#sex  and id in
        <foreach collection="idx" item="tid" open="(" close=")" separator=",">
            #tid
        </foreach>
    </select>

测试代码

 sqlSession = MyBatisUtil.createSqlSession();
        Map<String,Object> map=new HashMap<>();
        List<Integer> idx=new ArrayList();
        idx.add(1);
        idx.add(2);
        idx.add(3);
        map.put("sex","男");
        map.put("idx",idx);
        List<Student> students = sqlSession.getMapper(StudentMapper.class).getMapStudentList(map);
        sqlSession.commit();
        System.out.println("查询指定指定id的List集合的数据");
        System.out.println(students.toString());

图4 效果图

3.8小结

  1. mybatis可以接收的数据类型,基本的,对象,List,数组和map
  2. 不论是哪一种都可以放到map集合中去
  3. 放入map的之后会发生一定的变化,传入的值的类型变成了key的值的类型
  4. 入参的对象是基本类型就是key
  5. 入参的基本类型是对象,对象的属性就是key
  6. 入参的对象是list,默认的值就是list
  7. 入参的对象是数组,默认就是array
  8. 使用map键的值就和原来是一样的

3.9choose

原理和jstl以及用法都是类型的

  • choose,进行判断的条件
  • when,当条件符合的时候使用
  • otherwise,当所有的情况都不是符合的时候采用

案例:根据id,name 进行查询,只提供一个即可,如果不提供的话默认的是根据性别进行查询

接口

//    根据id,name 进行查询,只提供一个即可,如果不提供的话默认的是查询默认男性的学生的信息
List<Student> getMapStudentChoose(@Param("id") Integer id,@Param("name")String name,@Param("sex") String sex);

sql

    <select id="getMapStudentChoose" resultMap="getIdsStudentMap">
select * from student where 1=1
<choose>
    <when test="id!=null">and id=#id</when>
    <when test="name!=null">and name=#name</when>
    <otherwise> and sex=#sex</otherwise>
</choose>
    </select>

测试代码

    @Test
    public void getMapStudentChooseTest() 
        SqlSession sqlSession = null;
        try 
            sqlSession = MyBatisUtil.createSqlSession();
            List<Student> students = sqlSession.getMapper(StudentMapper.class).getMapStudentChoose(null,null,"男");
            sqlSession.commit();
            System.out.println("采用choose的查询的方式");
            System.out.println(students.toString());
         catch (Exception e) 
            e.printStackTrace();
         finally 
            MyBatisUtil.closeSqlSession(sqlSession);
        
    

图6 采用choose查询所有学生的信息

3.10分页

基于内存的分页。先查询出来所有的记录然后再进行根据起始的位置和容量进行取出数据。

案例:查询所有学生的信息,按照id进行降序。并且每次取出的数据为2条。

注意:分页的起点是从0开始的,也就是说limit后面的第一个数字就是起点的位置就是0

接口

    /*
    * currentPage当前是哪一页
    * pageSize要分页的大小
    * */
  List<Student> getPage (@Param("currentPage") Integer currentPage,@Param("pageSize") Integer pageSize);

sql

<!--    分页-->
    <select id="getPage" resultMap="getIdsStudentMap">
        select * from student
            order by id desc
            limit #currentPage,#pageSize
    </select>

测试代码

 sqlSession = MyBatisUtil.createSqlSession();
        List<Student> students = sqlSession.getMapper(StudentMapper.class).getPage(0,2);
        System.out.println("分页查询");
        System.out.println(students.toString());

19.Mybatis之动态SQL

  MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦。例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。
  虽然在以前使用动态 SQL 并非一件易事,但正是 MyBatis 提供了可以被用在任意 SQL 映射语句中的强大的动态 SQL 语言得以改进这种情形。
  动态 SQL 元素和 JSTL 或基于类似 XML 的文本处理器相似。在 MyBatis 之前的版本中,有很多元素需要花时间了解。MyBatis 3 大大精简了元素种类,现在只需学习原来一半的元素便可。MyBatis 采用功能强大的基于 OGNL 的表达式来淘汰其它大部分元素。

1.if语句

  动态 SQL 通常要做的事情是根据条件包含 where 子句的一部分。

<?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">
  <mapper namespace="com.sxt.dao.UserMapper">
      <select id="query" resultType="user" parameterType="user">
          select
              *
          from
              t_user
          where
              1=1
          <if test="name!=null">
              and name=#name
          </if>
          <if test="age>0">
              and age=#age
          </if>
          <if test="id!=null and id>0">
              and id=#id
          </if>
      </select>

  测试

@Test
    public void test1() throws IOException 
        InputStream in = Resources.getResourceAsStream("mybatis-cfg.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        SqlSession session = factory.openSession();
        UserMapper dao = session.getMapper(UserMapper.class);
        User user = new User();
        user.setName("王五");
        user.setId(2);
        user.setAge(18);
        List<User> list = dao.query(user);
        for (User user2 : list) 
            System.out.println(user2);
        
        session.close();
    

  结果

技术图片

2.where语句

<select id="query1" resultType="user" parameterType="user">
          select
              *
          from
              t_user
          <where>
              <if test="name!=null">
                  and name=#name
              </if>
              <if test="age>0">
                  and age=#age
              </if>
              <if test="id!=null and id>0">
                  and id=#id
              </if>
          </where>
      </select>

  测试

@Test
    public void test2() throws IOException 
        InputStream in = Resources.getResourceAsStream("mybatis-cfg.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        SqlSession session = factory.openSession();
        UserMapper dao = session.getMapper(UserMapper.class);
        User user = new User();
//        user.setName("王五");
//        user.setId(2);
//        user.setAge(18);
        List<User> list = dao.query1(user);
        for (User user2 : list) 
            System.out.println(user2);
        
        session.close();
    

  结果

技术图片

3.choose语句

<!-- 首先判断name是否为空 如果不为空根据name查询 结束
          如果name为空 判断age是否传达 ,不为空大于0根据age查询
          否则根据id倒叙
       -->
      <select id="query2" resultType="user" parameterType="user">
          select
              *
          from
              t_user
          where 1=1
          <choose>
              <when test="name!=null">
                  and name=#name
              </when>
              <when test="age!=null and age>0">
                  and age=#age
              </when>
              <otherwise>
                  order by desc
              </otherwise>
          </choose>
      </select>

  测试

@Test
    public void test3() throws IOException 
        InputStream in = Resources.getResourceAsStream("mybatis-cfg.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        SqlSession session = factory.openSession(true);
        UserMapper dao = session.getMapper(UserMapper.class);
        User user = new User();
//        user.setName("王五");
//        user.setAge(18);
        List<User> list = dao.query2(user);
        for (User user2 : list) 
            System.out.println(user2);
        
        session.close();
    

  结果

技术图片

4.set语句

<!-- set标签会截取最后一个"," -->
      <update id="updateUser2" parameterType="user">
          update
              t_user
          <set>
              <if test="name!=null">
                  name=#name,
              </if>
              <if test="age!=null and age>0">
                  age=#age,
              </if>
          </set>
          where
              id=#id
      </update>

  测试

@Test
    public void test4() throws IOException 
        InputStream in = Resources.getResourceAsStream("mybatis-cfg.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        SqlSession session = factory.openSession(true);
        UserMapper dao = session.getMapper(UserMapper.class);
        User user = new User();
        user.setId(3);
        user.setName("渣渣");
        user.setAge(1);
        dao.updateUser2(user);
        session.close();
    

  结果

技术图片

5.trim语句

  trim标记是一个格式化的标记,可以完成set或者是where标记的功能

<select id="query3" resultType="user" parameterType="user">
          select
              *
          from
              t_user
          <trim prefix="where" prefixOverrides="and">
              <if test="name!=null">
                  and name=#name
              </if>
              <if test="age>0">
                  and age=#age
              </if>
              <if test="id!=null and id>0">
                  and id=#id
              </if>
          </trim>
      </select>
      

  测试

@Test
    public void test5() throws IOException 
        InputStream in = Resources.getResourceAsStream("mybatis-cfg.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        SqlSession session = factory.openSession();
        UserMapper dao = session.getMapper(UserMapper.class);
        User user = new User();
//        user.setName("王五");
//        user.setId(2);
//        user.setAge(18);
        List<User> list = dao.query3(user);
        for (User user2 : list) 
            System.out.println(user2);
        
        session.close();
    
    

  结果

技术图片

6.update语句

<update id="updateUser3" parameterType="user">
          update
              t_user
          <trim prefix="set" suffixOverrides=",">
              <if test="name!=null">
                  name=#name,
              </if>
              <if test="age!=null and age>0">
                  age=#age,
              </if>
          </trim>
          where
              id=#id
      </update>

  测试

@Test
    public void test6() throws IOException 
        InputStream in = Resources.getResourceAsStream("mybatis-cfg.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        SqlSession session = factory.openSession(true);
        UserMapper dao = session.getMapper(UserMapper.class);
        User user = new User();
        user.setName("花花");
        user.setId(5);
//        user.setAge(1);
        Integer count = dao.updateUser3(user);
        System.out.println(count);
        session.close();
    

  结果

技术图片

7.sql块

  sql片段一般用来定义sql中的列

<sql id="baseSql">
          id,name,age
      </sql>
      
      <select id="query4" resultType="user" parameterType="user">
          select
              <include refid="baseSql"></include>
          from
              t_user
          <trim prefix="where" prefixOverrides="and">
              <if test="name!=null">
                  and name=#name
              </if>
              <if test="age>0">
                  and age=#age
              </if>
              <if test="id!=null and id>0">
                  and id=#id
              </if>
          </trim>
      </select>

  测试

@Test
    public void test7() throws IOException 
        InputStream in = Resources.getResourceAsStream("mybatis-cfg.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        SqlSession session = factory.openSession();
        UserMapper dao = session.getMapper(UserMapper.class);
        User user = new User();
//        user.setName("王五");
//        user.setId(2);
//        user.setAge(18);
        List<User> list = dao.query4(user);
        for (User user2 : list) 
            System.out.println(user2);
        
        session.close();
    

  结果

技术图片

 

以上是关于MyBatis之动态sql的主要内容,如果未能解决你的问题,请参考以下文章

四动态 SQLSQL 语句构建器(笔记)

Java框架之MyBatis 07-动态SQL-缓存机制-逆向工程-分页插件

SQLsql的数学基石之关系代数与关系运算详解

mybatis-基于xml的多表查询

精通Mybatis之动态sql全流程解析

精通Mybatis之动态sql全流程解析