小黑子—MyBatis:第四章

MyBatis入门4.0

  • [十 小黑子进行MyBatis参数处理](#十 小黑子进行MyBatis参数处理)
    • [10.1 单个简单类型参数](#10.1 单个简单类型参数)
      • [10.1.1 单个参数Long类型](#10.1.1 单个参数Long类型)
      • [10.1.2 单个参数Date类型](#10.1.2 单个参数Date类型)
    • [10.2 Map参数](#10.2 Map参数)
    • [10.3 实体类参数(POJO参数)](#10.3 实体类参数(POJO参数))
    • [10.4 多参数](#10.4 多参数)
    • [10.5 @Param注解(命名参数)](#10.5 @Param注解(命名参数))
    • [10.6 @Param注解源码分析](#10.6 @Param注解源码分析)
  • [十一 小黑子的MyBatis查询专题](#十一 小黑子的MyBatis查询专题)
    • [11.1 返回Car](#11.1 返回Car)
    • [11.2 返回List< Car >](#11.2 返回List< Car >)
    • [11.3 返回Map](#11.3 返回Map)
      • [11.3.1 返回List< Map >](#11.3.1 返回List< Map >)
    • [11.4 返回Map<String.Map>](#11.4 返回Map<String.Map>)
    • [11.5 resultMap结果映射](#11.5 resultMap结果映射)
      • [11.5.1 开启驼峰命名自动映射](#11.5.1 开启驼峰命名自动映射)
    • 11.6返回总记录条数
  • [十二 小黑子的动态SQL](#十二 小黑子的动态SQL)
    • [12.1 if标签](#12.1 if标签)
    • [12.2 where标签](#12.2 where标签)
    • [12.3 trim标签](#12.3 trim标签)
    • [12.4 set标签](#12.4 set标签)
    • [12.5 chose when otherwise标签](#12.5 chose when otherwise标签)
    • [12.6 foreach标签](#12.6 foreach标签)
      • [12.6.1 批量删除](#12.6.1 批量删除)
      • [12.6.2 批量插入](#12.6.2 批量插入)
    • [12.7 sql标签和include标签](#12.7 sql标签和include标签)

十 小黑子进行MyBatis参数处理

10.1 单个简单类型参数

简单类型包括:

  • byte short int long float double char
  • Byte Short Integer Long Float Double Character
  • String
  • java.util.Date
  • java.sql.Date

简单类型对于mybatis来说都是可以自动类型识别的:

  • 也就是说对于mybatis来说,它是可以自动推断出ps.setXxxx()方法的。ps.setString()还是ps.setInt()。它可以自动推断。

其实SQL映射文件中的配置比较完整的写法是:

xml 复制代码
<select id="selectByName" resultType="student" parameterType="java.lang.String">
  select * from t_student where name = #{name, javaType=String, jdbcType=VARCHAR}
</select>

其中sql语句中的javaType,jdbcType,以及select标签中的parameterType属性,都是用来帮助mybatis进行类型确定的。不过这些配置多数是可以省略的。因为mybatis它有强大的自动类型推断机制。

  • javaType:可以省略
  • jdbcType:可以省略
  • parameterType:可以省略

准备数据库:

目录展示:

10.1.1 单个参数Long类型

  • StudentMapper
java 复制代码
package com.powernode.mybatis.mapper;

import com.powernode.mybatis.pojo.Student;

import java.util.Date;
import java.util.List;

public interface StudentMapper {
    /**
     * 当接口中的方法的参数只有一个(单给参数),并且参数的数据类型都是简单类型
     * 根据id查询、name查询、birth查询、sex查询
     * @version 1.0
    */

    List<Student> selectById(Long id);
    List<Student> selectByName(String name);
    List<Student> selectByBirth(Date birth);
    List<Student> selectBySex(Character sex);
}
  • StudentMappper.xml
xml 复制代码
<?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.powernode.mybatis.mapper.StudentMapper">
<!--
    List<Student> selectById(int id);
    List<Student> selectByName(String name);
    List<Student> selectByBirth(String birth);
    List<Student> selectBySex(String sex);

    parameterType属性的作用:
        告诉mybatis框架,我这个方法的参数类型是什么类型
        mybatis框架自身带有类型自动推断机制,所以大部分情况下parameterType属性都是可以省略不写的

    SQL语句最终是这样的:
        select * from t_student where id = ?
    JDBC代码是一定要给?传值的,
    怎么传值?ps.setXxx(第几个问好,传什么值);
           ps.setLong(1,1L)
           ps.setString(1,"zhangsan")
           ps.setDate(1,new Date())
           ps.setInt(1,100)
           ...
     mybatis底层到底调用setXxx的哪个方法,取决于parameterType属性的值
-->

    <select id="selectById" resultType="Student" parameterType="java.lang.Long">
        select * from t_student where id = #{id}
    </select>

</mapper>
  • 测试
java 复制代码
package com.powernode.mybatis.test;

import com.powernode.mybatis.mapper.StudentMapper;
import com.powernode.mybatis.pojo.Student;
import com.powernode.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class StudentMapperTest {
    @Test
    public void SelectById(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> students = mapper.selectById(1L);

        students.forEach(student -> System.out.println(student));

        sqlSession.commit();
        sqlSession.close();
    }
}

10.1.2 单个参数Date类型

xml 复制代码
<?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.powernode.mybatis.mapper.StudentMapper">
<!--
    List<Student> selectById(int id);
    List<Student> selectByName(String name);
    List<Student> selectByBirth(String birth);
    List<Student> selectBySex(String sex);

    parameterType属性的作用:
        告诉mybatis框架,我这个方法的参数类型是什么类型
        mybatis框架自身带有类型自动推断机制,所以大部分情况下parameterType属性都是可以省略不写的

    SQL语句最终是这样的:
        select * from t_student where id = ?
    JDBC代码是一定要给?传值的,
    怎么传值?ps.setXxx(第几个问好,传什么值);
           ps.setLong(1,1L)
           ps.setString(1,"zhangsan")
           ps.setDate(1,new Date())
           ps.setInt(1,100)
           ...
     mybatis底层到底调用setXxx的哪个方法,取决于parameterType属性的值
-->

    <select id="selectById" resultType="Student" parameterType="java.lang.Long">
        select * from t_student where id = #{id}
    </select>
    
    <select id="selectByName" resultType="Student">
        select * from t_student where name = #{name,javaType=String,jdbcType=VARCHAR}
    </select>

    <select id="selectByBirth" resultType="Student">
        select * from t_student where birth = #{birth}
    </select>

    <select id="selectBySex" resultType="Student">
        select * from t_student where sex = #{sex}
    </select>

</mapper>
  • 测试
java 复制代码
package com.powernode.mybatis.test;

import com.powernode.mybatis.mapper.StudentMapper;
import com.powernode.mybatis.pojo.Student;
import com.powernode.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

public class StudentMapperTest {

    @Test
    public void SelectBySex(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        Character sex = Character.valueOf('男');

        List<Student> students = mapper.selectBySex(sex);
        students.forEach(student -> System.out.println(student));

        sqlSession.commit();
        sqlSession.close();
    }

    @Test
    public void SelectByBirth() throws ParseException {
        SqlSession sqlSession = SqlSessionUtil.openSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date birth = sdf.parse("1980-10-11");

        List<Student> students = mapper.selectByBirth(birth);
        students.forEach(student -> System.out.println(student));

        sqlSession.commit();
        sqlSession.close();
    }

    @Test
    public void SelectByName(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> students = mapper.selectByName("李四");
        students.forEach(student -> System.out.println(student));

        sqlSession.commit();
        sqlSession.close();
    }


    @Test
    public void SelectById(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> students = mapper.selectById(1L);

        students.forEach(student -> System.out.println(student));

        sqlSession.commit();
        sqlSession.close();
    }
}

10.2 Map参数

这种方式是手动封装Map集合,将每个条件以key和value的形式存放到集合中。然后在使用的时候通过#{map集合的key}来取值

需求:根据map集合保存学生信息

  • StudentMapper接口:
java 复制代码
    int insertStudentByMap(Map<String,Object> map);
  • StudentMapper.xml
xml 复制代码
    <insert id="insertStudentByMap" parameterType="map">
        insert into t_student(id,name,age,sex,birth,height) value (null,#{姓名},#{年龄},#{性别},#{生日},#{身高})
    </insert>
  • 测试
java 复制代码
@Test
    public void InsertStudentByMap(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

        Map<String,Object> map = new HashMap<>();
        map.put("姓名","麻瓜");
        map.put("年龄",25);
        map.put("身高",1.82);
        map.put("性别",'男');
        map.put("生日",new Date());

        mapper.insertStudentByMap(map);

        sqlSession.commit();
        sqlSession.close();
    }


10.3 实体类参数(POJO参数)

使用实体类参数这里需要注意的是:#{} 里面写的是属性名字。这个属性名其本质上是:set/get方法名去掉set/get之后的名字

  • StudentMapper.xml
xml 复制代码
    <insert id="insertStudentByPOJO">
        insert into t_student(id,name,age,sex,birth,height) value (null,#{name},#{age},#{sex},#{birth},#{height})
    </insert>
  • StudentMapper接口
java 复制代码
/*
     * @description: 保存学生信息,通过实体类参数
     * @param student
     * @version 1.0
    */
    int insertStudentByPOJO(Student student);
  • 测试
java 复制代码
 @Test
    public void InsertStudentByPOJO(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

        Student student = new Student();
        student.setName("小老板");
        student.setAge(24);
        student.setSex('男');
        student.setBirth(new Date());
        student.setHeight(1.78);

        mapper.insertStudentByPOJO(student);

        sqlSession.commit();
        sqlSession.close();
    }


10.4 多参数

需求:通过name和sex查询

  • StudentMapper.xml
xml 复制代码
    <select id="selectByNameAndSex" resultType="Student">
        select * from t_student where name = #{name} and sex = #{sex}
    </select>
  • StudentMapper接口
java 复制代码
    /*
     * 这是多参数
     * 根据name和sex查询Student信息
     * 如果是多个参数的话,mybatis框架底层是怎么做到的呢?
     *      mybatis框架会自动创建一个Map集合,并且Map集合是以这种方式储存参数的:
     *          map.put("arg0",name);
     *          map.put("arg1",sex);
     *          map.put("arg1",sex);
     *          map.put("param1",name);
     *          map.put("param2",sex);
    */
    List<Student> selectByNameAndSex(String name,Character sex);
  • 测试
java 复制代码
  @Test
    public void selectByNameAndSex(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> students = mapper.selectByNameAndSex("张三", '男');
        students.forEach(student -> System.out.println(student));

        sqlSession.commit();
        sqlSession.close();
    }

异常信息描述了:name参数找不到,可用的参数包括[arg1, arg0, param1, param2]

修改StudentMapper.xml配置文件:尝试使用[arg1, arg0, param1, param2]去参数

  • 修改StudentMapper.xml文件
xml 复制代码
    <select id="selectByNameAndSex" resultType="Student">
       <!--  select * from t_student where name = #{name} and sex = #{sex}  -->
            select * from t_student where name = #{arg0} and sex = #{param2}
    </select>
  • 再次尝试修改StudentMapper.xml文件
xml 复制代码
<select id="selectByNameAndSex" resultType="Student">
  <!--select * from t_student where name = #{name} and sex = #{sex}-->
  <!--select * from t_student where name = #{arg0} and sex = #{arg1}-->
  <!--select * from t_student where name = #{param1} and sex = #{param2}-->
  select * from t_student where name = #{arg0} and sex = #{param2}
</select>

通过测试可以看到:

  • arg0 是第一个参数
  • param1是第一个参数
  • arg1 是第二个参数
  • param2是第二个参数

实现原理:实际上在mybatis底层会创建一个map集合,以arg0/param1为key,以方法上的参数为value,例如以下代码:

java 复制代码
Map<String,Object> map = new HashMap<>();
map.put("arg0", name);
map.put("arg1", sex);
map.put("param1", name);
map.put("param2", sex);

// 所以可以这样取值:#{arg0} #{arg1} #{param1} #{param2}
// 其本质就是#{map集合的key}

注意:使用mybatis3.4.2之前的版本时:要用#{0}和#{1}这种形式。

10.5 @Param注解(命名参数)

可以不用arg0 arg1 param1 param2吗?这个map集合的key我们自定义可以吗?当然可以。使用@Param(" 注解的名称 ")注解即可。这样可以增强可读性。

需求:根据name和age查询

  • StudentMapper接口
java 复制代码
    /*
     * Param注解
     *
     * mybatis框架底层的实现原理:
     *    map.put("name",name);
     *    map.put("sex",sex);
     * @param name
     * @param sex
     *
    */
    List<Student> selectByNameAndSex2(@Param("name")String name,@Param("sex") Character sex);
  • StudentMapper.xml
xml 复制代码
    <select id="selectByNameAndSex2" resultType="Student">
        <!-- 使用了@Param注解之后,arg0和arg1失效了,但是param1和param2还可以用  -->
        select * from t_student where name = #{name} and sex and #{sex}
    </select>
  • 测试
java 复制代码
@Test
    public void SelectByNameAndSex2(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> students = mapper.selectByNameAndSex2("张三", '男');
        students.forEach(student -> System.out.println(student));

        sqlSession.commit();
        sqlSession.close();
    }

核心:@Param("这里填写的其实就是map集合的key")

10.6 @Param注解源码分析

做个了解

十一 小黑子的MyBatis查询专题

模块名:mybatis-007-select

打包方式:jar

引入依赖:mysql驱动依赖、mybatis依赖、logback依赖、junit依赖。

引入配置文件:jdbc.properties、mybatis-config.xml、logback.xml

创建pojo类:Car

创建Mapper接口:CarMapper

创建Mapper接口对应的映射文件:com/powernode/mybatis/mapper/CarMapper.xml

创建单元测试:CarMapperTest

拷贝工具类:SqlSessionUtil

11.1 返回Car

当查询的结果,有对应的实体类,并且查询结果只有一条时:

  • CarMapper.xml
xml 复制代码
<?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.powernode.mybatis.mapper.CarMapper">

    <select id="selectById" resultType="Car">
        select
               id,
               car_num as carNum,
               brand,
               guide_price as guidePrice,
               produce_time as produceTime,
               car_type as carType
        from t_car
        where
            id = #{id}
    </select>

</mapper>
  • CarMapper接口
java 复制代码
package com.powernode.mybatis.mapper;

import com.powernode.mybatis.pojo.Car;

public interface CarMapper {

    /**
     * 根据id主键查询:结果最多只有一条
     * @param id
     * @return
     */
    Car selectById(Long id);

}
  • 测试
java 复制代码
package com.powernode.mybatis.test;

import com.powernode.mybatis.mapper.CarMapper;
import com.powernode.mybatis.pojo.Car;
import com.powernode.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

public class CarMapperTest {
    @Test
    public void testSelectById(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        Car car = mapper.selectById(1L);
        System.out.println(car);

        sqlSession.commit();
        sqlSession.close();
    }

}

当返回记录结果有多条,却用单个实体类接收时:

  • CarMapper接口
java 复制代码
/*
     * @description: 根据品牌进行模糊查询
     * 查询的结果可能有多个,但是采用一个POJO对象来接收的问题
     * @param brand
     * @version 1.0
    */
    Car selectByBrandLike(String brand);
  • CarMapper.xml
xml 复制代码
<select id="selectByBrandLike" resultType="Car">
        select
            id,
            car_num as carNum,
            brand,
            guide_price as guidePrice,
            produce_time as produceTime,
            car_type as carType
        from t_car
        where
            brand like "%"#{brand}"%"
    </select>
  • 测试
java 复制代码
 @Test
    public void testSelectByBrandLike(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);

        //出现异常TooManyResultsException
        //什么意思?你期望的结果是返回一条记录,但是实际的SQL语句在执行的时候,返回的记录条数不是一条,是多条
        Car car = mapper.selectByBrandLike("byd");
        System.out.println(car);

        sqlSession.commit();
        sqlSession.close();
    }

11.2 返回List< Car >

一、采用List集合接收多条数据,模糊查询

  • CarMappper接口
java 复制代码
List<Car> selectByBrandLike2(String brand);
  • CarMapper.xml
xml 复制代码
  <select id="selectByBrandLike2" resultType="Car">
        select
            id,
            car_num as carNum,
            brand,
            guide_price as guidePrice,
            produce_time as produceTime,
            car_type as carType
        from t_car
        where
            brand like "%"#{brand}"%"
    </select>
  • 测试
java 复制代码
@Test
    public void testSelectByBrandLike2(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        List<Car> cars = mapper.selectByBrandLike2("byd");
        cars.forEach(car -> System.out.println(car));

        sqlSession.commit();
        sqlSession.close();
    }

二、

根据id查询Car,id是主键。这个结果一定是一条,不可能有多条数据。所以返回可以用List< Car >集合进行接收。

  • CarMapper.xml
xml 复制代码
    <select id="selectById2" resultType="Car">
        select
            id,
            car_num as carNum,
            brand,
            guide_price as guidePrice,
            produce_time as produceTime,
            car_type as carType
        from t_car
        where
            id = #{id}
    </select>
  • CarMapper接口
java 复制代码
    /*
     * @description: 根据id查询Car,id是主键。这个结果一定是一条,不可能有多条数据。
     * @param id
     * @version 1.0
    */
    List<Car> selectById2(Long id);
  • 测试
java 复制代码
  @Test
    public void testSelectById2(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        List<Car> cars = mapper.selectById2(2L);
        System.out.println(cars);

        sqlSession.commit();
        sqlSession.close();
    }

11.3 返回Map

当返回的数据,没有合适的实体类对应的话,可以采用Map集合接收。字段名做key,字段值做value。

查询如果可以保证只有一条数据,则返回一个Map集合即可。

  • CarMappper.xml
xml 复制代码
    <!-- resultType="java.util.map"有别名 map -->
    <select id="selectByIdRetMap" resultType="map">
        select * from t_car where id = #{id}
    </select>
  • CarMapper接口
java 复制代码
    /*
     * @description: 根据id获取汽车信息。将汽车信息放到Map集合中
     * @param id
     * @version 1.0
    */
    Map<String,Object> selectByIdRetMap(Long id);
  • 测试
java 复制代码
    @Test
    public void testSelectByIdRetMap(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        Map<String, Object> car = mapper.selectByIdRetMap(34L);
        System.out.println(car);
        sqlSession.commit();
        sqlSession.close();
    }

11.3.1 返回List< Map >

查询结果条数大于等于1条数据,则可以返回一个存储Map集合的List集合

resultMap="map",这是因为mybatis内置了很多别名。【参见mybatis开发手册】

  • CarMapper.xml
xml 复制代码
    <!-- 这个resultType不是list,是map-->
    <select id="selectAllRetListMap" resultType="map">
        select * from t_car
    </select>
  • CarMapper接口
java 复制代码
 /*
     * 查询所有的Car信息,返回一个存放Map集合的List集合
     * @version 1.0
    */
    List<Map<String,Object>> selectAllRetListMap();
  • 测试
java 复制代码
    @Test
    public  void testSelectAllRetListMap(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        List<Map<String, Object>> maps = mapper.selectAllRetListMap();
        maps.forEach(map -> System.out.println(map));
        sqlSession.commit();
        sqlSession.close();
    }

当然,如果返回一个Map集合,可以将Map集合放到List集合中吗?当然可以,这里就不再测试了。

反过来,如果返回的不是一条记录,是多条记录的话,只采用单个Map集合接收,这样同样会出现之前的异常:TooManyResultsException

11.4 返回Map<String.Map>

拿Car的id做key,以后取出对应的Map集合时更加方便

  • CarMapper接口
java 复制代码
    /*
     * 查询所有的Car,返回一个大Map集合
     * Map集合的key是每条记录的主键值
     * map集合的value是每条记录
    */
    @MapKey("id")//将查询结果的id值作为整个大Map集合的key
    Map<Long,Map<String,Object>> selectAllRetMap();
  • 测试
java 复制代码
@Test
    public void testSelectAllRetMap(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        Map<Long, Map<String, Object>> maps = mapper.selectAllRetMap();
        System.out.println(maps);
        sqlSession.commit();
        sqlSession.close();
    }
  • CarMapper.xml
xml 复制代码
    <select id="selectAllRetMap" resultType="map">
        select * from t_car
    </select>

返回结果一个大Map集合:

xml 复制代码
{1={car_num=1001, id=1, guide_price=10, produce_time=2022-10-11, brand=宝马520, car_type=燃油车}, 
2={car_num=1111, id=2, guide_price=10, produce_time=2020-11-11, brand=byd, car_type=电车}, 
34={car_num=9991, id=34, guide_price=40, produce_time=2022-11-11, brand=凯迪, car_type=能源车}, 
3={car_num=1111, id=3, guide_price=10, produce_time=2020-11-11, brand=byd, car_type=电车}, 
4={car_num=9999, id=4, guide_price=30, produce_time=1999-11-10, brand=magua, car_type=旧能源}, 
6={car_num=8888, id=6, guide_price=30, produce_time=2000-11-66, brand=法克鱿, car_type=捞车}, 
7={car_num=8888, id=7, guide_price=30, produce_time=2000-11-66, brand=法克鱿, car_type=捞车}, 
8={car_num=8888, id=8, guide_price=30, produce_time=2000-11-66, brand=法克鱿, car_type=捞车}, 
9={car_num=8888, id=9, guide_price=30, produce_time=2000-11-66, brand=法克鱿, car_type=捞车}, 
10={car_num=8888, id=10, guide_price=30, produce_time=2000-11-66, brand=法克鱿, car_type=捞车}, 
15={car_num=22222, id=15, guide_price=3, produce_time=2022-10-1, brand=小老板, car_type=新能源}}

11.5 resultMap结果映射

查询结果的列名和java对象的属性名对应不上怎么办?

  1. 第一种方式:as 给列起别名
  2. 第二种方式:使用resultMap进行结果映射
  3. 第三种方式:是否开启驼峰命名自动映射(配置settings)

使用resultMap进行结果映射:

  • CarMapper接口
java 复制代码
    /**
     * 查询所有Car,使用resultMap进行结果映射
     * @return
     */
    List<Car> selectAllByResultMap();
  • CarMapper.xml
xml 复制代码
    <!--
        1.专门定义一个结果映射,在这个结果映射当中指定数据库的字段名和Java类的属性名的对应关系
        2.type属性:用来指定POJO类的类名
        3.id属性:指定resultMap的唯一标识。这个id将来要在select标签中使用
    -->
    <resultMap id="carResultMap" type="Car">
        <!--如果数据库表中有主键,一般都是有主键,要不然不符合数据库设计的第一范式-->
        <!--如果有主键,建议这里配置一个id标签,注意:这不是必须的。但是官方的解释是什么?这样配置可以让mybatis提供效率-->

        <id property="id" column="id"></id>

        <!--property后面接的是POJO类的属性名-->
        <!--column后面接的是数据库的字段名-->

        <result property="carNum" column="car_num" javaType="java.lang.String" jdbcType="VARCHAR"/>
        <!--如果column和property是一样的,这个可以省略。-->
        <!--        <result property="brand" column="brand"/>-->
        <result property="guidePrice" column="guide_price"/>
        <result property="produceTime" column="produce_time"/>
        <result property="carType" column="car_type" javaType="string" jdbcType="VARCHAR"/>


    </resultMap>

    <!--select标签的resultMap属性,用来指定使用哪个结果映射。resultMap后面的值是resultMap的id-->
    <select id="selectAllByResultMap" resultMap="carResultMap">
        select * from t_car
    </select>
  • 测试
java 复制代码
  @Test
    public void testSelectAllByResultMap(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        List<Car> cars = mapper.selectAllByResultMap();
        cars.forEach(car -> System.out.println(car));
        sqlSession.commit();
        sqlSession.close();
    }

11.5.1 开启驼峰命名自动映射

使用这种方式的前提是:属性名遵循Java的命名规范,数据库表的列名遵循SQL的命名规范。

Java命名规范:首字母小写,后面每个单词首字母大写,遵循驼峰命名方式。

SQL命名规范:全部小写,单词之间采用下划线分割。

比如以下的对应关系:

实体类中的属性名 数据库表的别名
carNum car_num
carType car_type
produceTime produce_time
  • 如何启用该功能,在mybatis-config.xml文件中进行配置:
xml 复制代码
<!--放在properties标签后面-->
<settings>
  <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
  • CarMapper接口
java 复制代码
/**
* 查询所有Car,启用驼峰命名自动映射
* @return
*/
List<Car> selectAllByMapUnderscoreToCamelCase();
  • CarMapper.xml
xml 复制代码
    <select id="selectAllByMapUnderscoreToCamelCase" resultType="car">
        select * from t_car
    </select>
  • 测试
java 复制代码
@Test
    public void testSelectAllByMapUnderscoreToCamelCase (){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        List<Car> cars = mapper.selectAllByMapUnderscoreToCamelCase();
        cars.forEach(car -> System.out.println(car));
        sqlSession.commit();
        sqlSession.close();
    }

11.6返回总记录条数

需求:查询总记录条数

  • CarMapper.xml
xml 复制代码
 <select id="selectTotal" resultType="Long">
        select count(*) from t_car
    </select>
  • CarMapper接口
java 复制代码
    /*
     * @description: 获取Car的总记录条数
     * @version 1.0
    */
    Long selectTotal();
  • 测试
java 复制代码
 @Test
    public void testSelectTotal(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        Long total = mapper.selectTotal();
        System.out.println(total);
        sqlSession.commit();
        sqlSession.close();
    }

十二 小黑子的动态SQL

什么是动态SQL?

有的业务场景,也需要SQL语句进行动态拼接,例如:

  • 批量删除

12.1 if标签

  1. if标签中test属性是必须的。
  2. if标签中test属性的值是false或者true。
  3. 如果test是true,则if标签中的sql语句就会拼接。反之,则不会拼接。
  4. test属性中可以使用的是:
    • 当使用了@Param注解,那么test中要出现的是@Param注解指定的参数名。@Param("brand"),那么这里只能使用brand
    • 当没有使在这里插入代码片@Param注解,那么test中要出现的是: param1 param2 param3 arg0 arg1 arg2. . . .
    • 当使用了POJO,那么test中出现的是POJO类的属性名。
  5. 在mybatis的动态SQL当中,不能使用&&,只能使用and。
  • CarMapper.xml
xml 复制代码
<?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.powernode.mybatis.mapper.CarMapper">

    <select id="selectByMultiCondition" resultType="Car">
        select * from t_car
        where
        <if test="brand != null and brand != ''">
            brand like "%"#{brand}"%"
        </if>
        <if test="guidePrice != null and guidePrice != ''">
            and guide_price > #{guidePrice}
        </if>
        <if test="carType != null and carType != ''">
            and car_type = #{carType}
        </if>
    </select>
</mapper>
  • CarMapper接口
java 复制代码
package com.powernode.mybatis.mapper;

import com.powernode.mybatis.pojo.Car;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface CarMapper {
    /*
     * 多条件查询
     * @param brand
     * @param guidePrice
     * @param carType
     * @version 1.0
    */
    List<Car> selectByMultiCondition(@Param("brand") String brand,@Param("guidePrice") Double guidePrice, @Param("carType") String carType);
}
  • 测试
java 复制代码
package com.powernode.mybatis.test;

import com.powernode.mybatis.mapper.CarMapper;
import com.powernode.mybatis.pojo.Car;
import com.powernode.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class CarMapperTest {
    @Test
    public void testSelectByMultiCondition(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);

        //假设三个条件都不是空
        List<Car> cars = mapper.selectByMultiCondition("byd", 2.0, "电车");
        cars.forEach(car -> System.out.println(car));

        sqlSession.commit();
        sqlSession.close();
    }
}

12.2 where标签

where标签的作用:让where子句更加动态智能。

所有条件都为空时,where标签保证不会生成where子句。

自动去除某些条件前面多余的andor。后面的无法去除

继续使用if标签中的需求。

  • CarMapper接口
java 复制代码
    /*
     * @description: where标签,让where子句更加的智能
     * @version 1.0
    */
    List<Car> selectByMultiConditionWithWhere(@Param("brand") String brand,@Param("guidePrice") Double guidePrice, @Param("carType") String carType);
  • CarMapper接口
xml 复制代码
  <select id="selectByMultiConditionWithWhere" resultType="Car">
        select * from t_car
        <!--where标签是专门负责where子句动态生成的-->
        <where>
            <if test="brand != null and brand != ''">
                brand like "%"#{brand}"%"
            </if>
            <if test="guidePrice != null and guidePrice != ''">
                and guide_price > #{guidePrice}
            </if>
            <if test="carType != null and carType != ''">
                and car_type = #{carType}
            </if>
        </where>
  • 测试
java 复制代码
    @Test
    public void selectByMultiConditionWithWhere(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);

        //假设三个条件都不是空
//        List<Car> cars = mapper.selectByMultiConditionWithWhere("byd", 2.0, "电车");

        //假设三个条件都是空,where标签可以自动判断是否符合条件
//        List<Car> cars = mapper.selectByMultiConditionWithWhere("", null, "");

        //假设一个条件为空,where标签也会自动判断消去and
        List<Car> cars = mapper.selectByMultiConditionWithWhere("", 2.0, "电车");
        cars.forEach(car -> System.out.println(car));

        //但是后面两个条件是空时,后面有and,where标签就无法去除

        sqlSession.commit();
        sqlSession.close();
    }

12.3 trim标签

trim标签的属性:

  • prefix:再trim标签中的语句前添加内容
  • suffix:再trim标签中的语句后添加内容
  • prefixOverrides:前缀覆盖掉(去掉)
  • suffixOverrides:后缀覆盖掉(去掉)
java 复制代码
    /*
     * @description: 使用trim标签
     * @version 1.0
     */
    List<Car> selectByMultiConditionWithTrim(@Param("brand") String brand,@Param("guidePrice") Double guidePrice, @Param("carType") String carType);
xml 复制代码
 <select id="selectByMultiConditionWithTrim" resultType="Car">
        <!--prefix="where" 是在trim标签所有内容的前面添加where-->
        <!--suffixOverrides="and|or" 把trim标签中内容的后缀and或or去掉,以至于后面有and或or的话程序也不会报错-->
        select * from t_car
        <trim prefix="where" suffixOverrides="and|or">
            <if test="brand != null and brand != ''">
                brand like "%"#{brand}"%" and
            </if>
            <if test="guidePrice != null and guidePrice != ''">
                 guide_price > #{guidePrice} and
            </if>
            <if test="carType != null and carType != ''">
                 car_type = #{carType}
            </if>
        </trim>
    </select>
java 复制代码
   @Test
    public void testSelectByMultiConditionWithTrim(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        List<Car> cars = mapper.selectByMultiConditionWithTrim("", null, "");
        cars.forEach(car -> System.out.println(car));

        sqlSession.commit();
        sqlSession.close();
    }

12.4 set标签

主要使用在update语句当中,用来生成set关键字,同时去掉最后多余的","

比如我们只更新提交的不为空的字段,如果提交的数据是空或者"",那么这个字段我们将不更新。

java 复制代码
    /*
     * @description: 使用set标签
     * @version 1.0
    */
    int updateBySet(Car car);
xml 复制代码
    <update id="updateBySet">
        update t_car
        <set>
            <if test="carNum != null and carNum != '' ">car_num = #{carNum},</if>
            <if test="brand != null and brand != '' ">brand = #{brand},</if>
            <if test="guidePrice != null and guidePrice != '' ">guide_price = #{guidePrice},</if>
            <if test="produceTime != null and produceTime != '' ">produce_time = #{produceTime},</if>
            <if test="carType != null and carType != '' ">car_type = #{carType}</if>
        </set>
        where
                id = #{id}
    </update>
java 复制代码
    @Test
    public void testUpdateBySet(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        Car car = new Car(34L, null, "麻瓜霸道", null, null, null);
        mapper.updateBySet(car);

        sqlSession.commit();
        sqlSession.close();
    }

12.5 chose when otherwise标签

这三个标签是在一起使用的:

语法格式:

xml 复制代码
<choose>
  <when></when>
  <when></when>
  <when></when>
  <otherwise></otherwise>
</choose>

等同于:

java 复制代码
if(){
    
}else if(){
    
}else if(){
    
}else if(){
    
}else{

}

只有一个分支会被选择!!!!

案例需求:先根据品牌查询,如果没有提供品牌,再根据指导价查询,如果没有提供指导架构,就根据生产日期查询

java 复制代码
    /**
     * 使用choose when otherwise标签查询
     * @param brand
     * @param guidePrice
     * @param carType
     * @return
     */
    List<Car> selectWithChoose(@Param("brand") String brand, @Param("guidePrice") Double guidePrice, @Param("carType") String carType);
xml 复制代码
 <select id="selectWithChoose" resultType="Car">
        select * from t_car
        <where>
            <choose>
                <when test="brand != null and brand != ''">
                    brand like "%"#{brand}"%"
                </when>
                <when test="guidePrice != null and guidePrice != ''">
                    guide_price > #{guidePrice}
                </when>
                <otherwise>
                    car_type = #{carType}
                </otherwise>
            </choose>
        </where>
    </select>
java 复制代码
 @Test
    public void testSelectWithChoose(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);

        //三个条件都不为空
//        List<Car> cars = mapper.selectWithChoose("麻瓜霸道", 1.0, "新能源");
        //第一个条件是空
        // List<Car> cars = mapper.selectWithChoose(null, 1.0, "新能源");
        //前两个条件是空
        // List<Car> cars = mapper.selectWithChoose(null, null, "新能源");
        //全都是空
         List<Car> cars = mapper.selectWithChoose(null, null, null);
        cars.forEach(car -> System.out.println(car));

        sqlSession.commit();
        sqlSession.close();
    }

12.6 foreach标签

循环数组或集合,动态生成sql,比如这样的SQL:

  • 批量删除
sql 复制代码
delete from t_car where id in(1,2,3);
delete from t_car where id = 1 or id = 2 or id = 3;
  • 批量增加
sql 复制代码
insert into t_car values
  (null,'1001','凯美瑞',35.0,'2010-10-11','燃油车'),
  (null,'1002','比亚迪唐',31.0,'2020-11-11','新能源'),
  (null,'1003','比亚迪宋',32.0,'2020-10-11','新能源')

12.6.1 批量删除

  1. in来删除

foreach标签属性:

  • collection:集合或数组
  • item:集合或数组中的元素
  • separator:循环之间的分隔符
  • open:foreach标签中所有内容的开始
  • close:foreach标签中所有内容的结束
java 复制代码
    /**
     * 通过foreach完成批量删除
     * @param ids
     * @return
     */
    int deleteBatchByForeach(@Param("ids") Long[] ids);
xml 复制代码
    <delete id="deleteBatchByForeach">
        delete from t_car where id in
        <foreach collection="ids" item="id" separator="," open="(" close=")">
            #{id}
        </foreach>
    </delete>
java 复制代码
    @Test
    public void testDeleteBatchByForeach(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);

        Long[] ids = {8L,9L,10L};
        mapper.deleteBatchByForeach(ids);

        sqlSession.commit();
        sqlSession.close();
    }


  1. 用or来删除
xml 复制代码
    <delete id="deleteById2" >
        delete from t_car where
        <foreach collection="ids" item="id" separator="or">
           id = #{id}
        </foreach>
    </delete>
java 复制代码
    /**
     * 通过id批量删除,使用or关键字
     * @param ids
     * @return
     */
    int deleteById2(@Param("ids") Long[] ids);
java 复制代码
  @Test
    public void testDeleteById2(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);

        Long[] ids = {35L,36L,37L};
        int count = mapper.deleteById2(ids);
        System.out.println(count);

        sqlSession.commit();
        sqlSession.close();
    }

12.6.2 批量插入

xml 复制代码
    <insert id="insertBatch">
        insert into t_car values
        <foreach collection="cars" item="car" separator=",">
            (null,#{car.carNum},#{car.brand},#{car.guidePrice},#{car.produceTime},#{car.carType})
        </foreach>
    </insert>
java 复制代码
    /**
     * 通过foreach批量插入,一次插入多条car信息
     * @param cars
     * @return
     */
    int insertBatch(@Param("cars") List<Car> cars);
java 复制代码
@Test
    public void testInsertBatchByForeach(){
        CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
        Car car1 = new Car(null, "2001", "兰博基尼", 100.0, "1998-10-11", "燃油车");
        Car car2 = new Car(null, "2001", "兰博基尼", 100.0, "1998-10-11", "燃油车");
        Car car3 = new Car(null, "2001", "兰博基尼", 100.0, "1998-10-11", "燃油车");
        List<Car> cars = Arrays.asList(car1, car2, car3);
        int count = mapper.insertBatch(cars);
        System.out.println("插入了几条记录" + count);
        SqlSessionUtil.openSession().commit();
    }


12.7 sql标签和include标签

sql标签用来声明sql片段

include标签用来将声明的sql片段包含到某个sql语句当中

作用:代码复用。易维护。

xml 复制代码
<!--声明一个SQL片段-->
<sql id="carCols">
	id,
	car_num as carNum,
	brand,
	guide_price as guidePrice,
	produce_time as produceTime,
	car_type as carType
</sql>

<select id="selectAllRetMap" resultType="map">
  select 
  	<!--将声明的sql片段包含进来-->
  	<include refid="carCols"/> 
  	from t_car
</select>

<select id="selectAllRetListMap" resultType="map">
  select 
  <include refid="carCols"/> 
  carType from t_car
</select>

<select id="selectByIdRetMap" resultType="map">
  select 
  <include refid="carCols"/> 
  from t_car 
  where id = #{id}
</select>
相关推荐
风景的人生10 小时前
mybatis映射时候的注意点
java·mybatis
玄〤10 小时前
MyBatis-Plus 核心功能详解:条件构造器、Service 封装与批量优化实践(黑马springcloud微服务课程)(day2)
spring cloud·微服务·mybatis
loading小马15 小时前
Mybatis-Plus超级实用的多种功能用法
java·spring boot·后端·maven·mybatis
高山上有一只小老虎19 小时前
mybatisplus分页查询版本 3.5.8 以下和版本 3.5.9及以上的区别
java·spring boot·mybatis
人道领域19 小时前
javaWeb从入门到进阶(MyBatis拓展)
java·tomcat·mybatis
J2虾虾1 天前
SpringBoot和mybatis Plus不兼容报错的问题
java·spring boot·mybatis
pp起床2 天前
【苍穹外卖】Day03 菜品管理
java·数据库·mybatis
九皇叔叔2 天前
【01】SpringBoot3 MybatisPlus 工程创建
java·mybatis·springboot3·mybatis plus
BD_Marathon2 天前
MyBatis逆向工程之清晰简洁版
mybatis
九皇叔叔2 天前
【02】SpringBoot3 MybatisPlus 加入日志功能
java·mysql·mybatis·日志·mybatisplus