小黑子—MyBatis:第四章

news2024/11/19 16:42:14

MyBatis入门4.0

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

<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
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 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>
  • 测试
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 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>
  • 测试
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接口:
    int insertStudentByMap(Map<String,Object> map);
  • StudentMapper.xml
    <insert id="insertStudentByMap" parameterType="map">
        insert into t_student(id,name,age,sex,birth,height) value (null,#{姓名},#{年龄},#{性别},#{生日},#{身高})
    </insert>
  • 测试
@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
    <insert id="insertStudentByPOJO">
        insert into t_student(id,name,age,sex,birth,height) value (null,#{name},#{age},#{sex},#{birth},#{height})
    </insert>
  • StudentMapper接口
/*
     * @description: 保存学生信息,通过实体类参数
     * @param student
     * @version 1.0
    */
    int insertStudentByPOJO(Student student);
  • 测试
 @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
    <select id="selectByNameAndSex" resultType="Student">
        select * from t_student where name = #{name} and sex = #{sex}
    </select>
  • StudentMapper接口

    /*
     * 这是多参数
     * 根据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);
  • 测试
  @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文件
    <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文件
<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,例如以下代码:

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接口
    /*
     * 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
    <select id="selectByNameAndSex2" resultType="Student">
        <!-- 使用了@Param注解之后,arg0和arg1失效了,但是param1和param2还可以用  -->
        select * from t_student where name = #{name} and sex and #{sex}
    </select>
  • 测试
@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 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接口
package com.powernode.mybatis.mapper;

import com.powernode.mybatis.pojo.Car;

public interface CarMapper {

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

}
  • 测试
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接口
/*
     * @description: 根据品牌进行模糊查询
     * 查询的结果可能有多个,但是采用一个POJO对象来接收的问题
     * @param brand
     * @version 1.0
    */
    Car selectByBrandLike(String brand);
  • CarMapper.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>
  • 测试
 @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接口
List<Car> selectByBrandLike2(String brand);
  • CarMapper.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>
  • 测试
@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
    <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接口
    /*
     * @description: 根据id查询Car,id是主键。这个结果一定是一条,不可能有多条数据。
     * @param id
     * @version 1.0
    */
    List<Car> selectById2(Long id);
  • 测试
  @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
    <!-- resultType="java.util.map"有别名 map -->
    <select id="selectByIdRetMap" resultType="map">
        select * from t_car where id = #{id}
    </select>

  • CarMapper接口
    /*
     * @description: 根据id获取汽车信息。将汽车信息放到Map集合中
     * @param id
     * @version 1.0
    */
    Map<String,Object> selectByIdRetMap(Long id);
  • 测试
    @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
    <!-- 这个resultType不是list,是map-->
    <select id="selectAllRetListMap" resultType="map">
        select * from t_car
    </select>
  • CarMapper接口
 /*
     * 查询所有的Car信息,返回一个存放Map集合的List集合
     * @version 1.0
    */
    List<Map<String,Object>> selectAllRetListMap();
  • 测试
    @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接口
    /*
     * 查询所有的Car,返回一个大Map集合
     * Map集合的key是每条记录的主键值
     * map集合的value是每条记录
    */
    @MapKey("id")//将查询结果的id值作为整个大Map集合的key
    Map<Long,Map<String,Object>> selectAllRetMap();
  • 测试
@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
    <select id="selectAllRetMap" resultType="map">
        select * from t_car
    </select>

返回结果一个大Map集合:

{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接口
    /**
     * 查询所有Car,使用resultMap进行结果映射
     * @return
     */
    List<Car> selectAllByResultMap();
  • CarMapper.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>
  • 测试
  @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命名规范:全部小写,单词之间采用下划线分割。

比如以下的对应关系:

实体类中的属性名数据库表的别名
carNumcar_num
carTypecar_type
produceTimeproduce_time
  • 如何启用该功能,在mybatis-config.xml文件中进行配置:
<!--放在properties标签后面-->
<settings>
  <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
  • CarMapper接口
/**
* 查询所有Car,启用驼峰命名自动映射
* @return
*/
List<Car> selectAllByMapUnderscoreToCamelCase();
  • CarMapper.xml
    <select id="selectAllByMapUnderscoreToCamelCase" resultType="car">
        select * from t_car
    </select>
  • 测试
@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
 <select id="selectTotal" resultType="Long">
        select count(*) from t_car
    </select>
  • CarMapper接口
    /*
     * @description: 获取Car的总记录条数
     * @version 1.0
    */
    Long selectTotal();
  • 测试
 @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 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接口
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);
}

  • 测试
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接口
    /*
     * @description: where标签,让where子句更加的智能
     * @version 1.0
    */
    List<Car> selectByMultiConditionWithWhere(@Param("brand") String brand,@Param("guidePrice") Double guidePrice, @Param("carType") String carType);
  • CarMapper接口
  <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>
  • 测试

    @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:后缀覆盖掉(去掉)
    /*
     * @description: 使用trim标签
     * @version 1.0
     */
    List<Car> selectByMultiConditionWithTrim(@Param("brand") String brand,@Param("guidePrice") Double guidePrice, @Param("carType") String carType);
 <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>
   @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关键字,同时去掉最后多余的“,”

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

    /*
     * @description: 使用set标签
     * @version 1.0
    */
    int updateBySet(Car car);
    <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>
    @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标签

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

语法格式:

<choose>
  <when></when>
  <when></when>
  <when></when>
  <otherwise></otherwise>
</choose>

等同于:

if(){
    
}else if(){
    
}else if(){
    
}else if(){
    
}else{

}

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

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

    /**
     * 使用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);
 <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>
 @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:

  • 批量删除
delete from t_car where id in(1,2,3);
delete from t_car where id = 1 or id = 2 or id = 3;
  • 批量增加
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标签中所有内容的结束
    /**
     * 通过foreach完成批量删除
     * @param ids
     * @return
     */
    int deleteBatchByForeach(@Param("ids") Long[] ids);
    <delete id="deleteBatchByForeach">
        delete from t_car where id in
        <foreach collection="ids" item="id" separator="," open="(" close=")">
            #{id}
        </foreach>
    </delete>
    @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来删除
    <delete id="deleteById2" >
        delete from t_car where
        <foreach collection="ids" item="id" separator="or">
           id = #{id}
        </foreach>
    </delete>
    /**
     * 通过id批量删除,使用or关键字
     * @param ids
     * @return
     */
    int deleteById2(@Param("ids") Long[] ids);
  @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 批量插入

    <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>
    /**
     * 通过foreach批量插入,一次插入多条car信息
     * @param cars
     * @return
     */
    int insertBatch(@Param("cars") List<Car> cars);
@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语句当中

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

<!--声明一个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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1088837.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CVE-2017-15715 apache换行解析文件上传漏洞

影响范围 httpd 2.4.0~2.4.29 复现环境 vulhub/httpd/CVE-2017-15715 docker-compose 漏洞原理 在apache2的配置文件&#xff1a; /etc/apache2/conf-available/docker-php.conf 中&#xff0c;php的文件匹配以正则形式表达 ".php$"的正则匹配模式意味着以.ph…

金蝶EAS、EAS Cloud远程代码执行漏洞

【漏洞概述】 金蝶 EAS 及 EAS Cloud 是金蝶软件公司推出的一套企业级应用软件套件&#xff0c;旨在帮助企业实现全面的管理和业务流程优化。 【漏洞介绍】 金蝶 EAS 及 EAS Cloud 存在远程代码执行漏洞 【影响版本】 金蝶 EAS 8.0&#xff0c;8.1&#xff0c;8.2&#xf…

风电光伏混合储能功率小波包分解、平抑前后波动性分析、容量配置、频谱分析、并网功率波动分析(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

流计算概述(林子雨慕课课程)

文章目录 11. 流计算概述11.1 流计算概述11.1.1 数据的处理模型11.1.2 流计算概念与典型框架 11.2 流计算处理流程11.3 流计算的应用11.4 开源流计算框架Storm11.4.1 Storm 简介11.4.2 Storm设计思想11.4.3 Storm框架设计 11.5 Spark Spark Streaming Samza以及三种流计算框架比…

Python如何17行代码画一个爱心

&#x1f308;write in front&#x1f308; &#x1f9f8;大家好&#xff0c;我是Aileen&#x1f9f8;.希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流. &#x1f194;本文由Aileen_0v0&#x1f9f8; 原创 CSDN首发&#x1f412; 如…

xtrabackup全备 增备

版本针对mysql8.0版本 官方下载地址 https://www.percona.com/downloads 自行选择下载方式 yum安装方式 1、下载上传服务器 安装软件 [rootmaster mysql]# ll percona-xtrabackup-80-8.0.33-28.1.el7.x86_64.rpm -rw-r--r--. 1 root root 44541856 Oct 10 13:25 percona-x…

android 判断是否打开了蓝牙网络共享

最近做项目遇到需要判断手机是否打开了蓝牙网络共享的开关 //调用isBluetoothPanTetheringOn(context) {if (it) {Log.i("TAG","已打开")} else {Log.i("TAG","未打开")context.gotoBleShareSettings()} }/*** 是否打开蓝牙网络共享**…

idea中取消class文件显示所有方法的显示

一 idea中class文件取消显示方法 1.1 取消显示方法 1.显示如下 2.操作如下 3.显示如下

2023年中国固废处理行业研究报告

第一章 行业概况 1.1 定义 固体废物处理是一个日益重要的领域&#xff0c;随着中国城市化进程的加速和工业产值的持续增长&#xff0c;固体废物的产生量也在不断上升。根据《固体废物污染环境防治法》的定义&#xff0c;固体废物包括了人类在生产、生活和其他活动中产生的固态…

基于单目的光流法测速

目录 1.简介 2.代码实现 1.简介 基于单目的光流法是一种常见的计算机视觉技术&#xff0c;用于估计图像序列中物体的运动速度。它通过分析连续帧之间的像素变化来推断物体在图像中的移动情况。 背景&#xff1a; 光流法是计算机视觉领域中最早的运动估计方法之一&#xff0c…

BUUCTF 金三 1

BUUCTF:https://buuoj.cn/challenges 题目描述&#xff1a; 只有一个附件&#xff0c;下载下来有一张GIF图片。 解题思路&#xff1a; 本题一共有2种解法&#xff08;本人找到的&#xff09; 方法一&#xff1a; 1、打开这张GIF图片&#xff0c;观察到不正常闪动&#xff0c;似…

《YOLO医学影像检测》专栏介绍 CSDN独家改进实战

&#x1f4a1;&#x1f4a1;&#x1f4a1;YOLO医学影像检测&#xff1a;http://t.csdnimg.cn/N4zBP ✨✨✨实战医学影像检测项目&#xff0c;通过创新点验证涨点可行性&#xff1b; ✨✨✨入门医学影像检测到创新&#xff0c;不断打怪进阶&#xff1b; 1.血细胞检测介绍 数据…

数据结构 - 2(顺序表10000字详解)

一&#xff1a;List 1.1 什么是List 在集合框架中&#xff0c;List是一个接口&#xff0c;继承自Collection。 Collection也是一个接口&#xff0c;该接口中规范了后序容器中常用的一些方法&#xff0c;具体如下所示&#xff1a; Iterable也是一个接口&#xff0c;Iterabl…

security+JWT

securityJWT 添加依赖准备工作sqlUserInfoUserMapperUserService、UserServiceImpl 创建JwtUtils工具类&#xff0c;做token的生成和校验进入Security创建AccountDetailsServiceImpl&#xff0c;并且实现UserDetailsService编写登录操作 创建拦截器JWTAuthenticationFilter继承…

mac电影特效合成软件nuke15 完美激活版下载

Nuke 15是一款由英国The Foundry公司开发的专业的合成软件&#xff0c;被广泛用于电影、电视和广告制作中的后期合成和特效制作。 Mac软件下载&#xff1a;nuke15 完美激活版下载 Win软件下载&#xff1a;NUKE 13 中文激活版 Nuke 15拥有强大的功能和灵活性&#xff0c;可以帮助…

TartanVO: A Generalizable Learning-based VO 服务器复现(rtx3090 py3)

源码地址 代码地址&#xff1a;https://github.com/castacks/tartanvo/tree/python3 配环境 git clone https://github.com/castacks/tartanvo.git -b python3创建conda环境&#xff1a; conda create -n tartanvo python3.8安装pytorch conda install pytorch1.10.1 torc…

路由router

什么是路由? 一个路由就是一组映射关系&#xff08;key - value&#xff09;key 为路径&#xff0c;value 可能是 function 或 component 2、安装\引入\基础使用 只有vue-router3&#xff0c;才能应用于vue2&#xff1b;vue-router4可以应用于vue3中 这里我们安装vue-router3…

elementUI el-table+树形结构子节点选中后没有打勾?(element版本问题 已解决)

问题 1.不勾选父级CB111&#xff0c;直接去勾选子级&#xff08;ST2001…&#xff09;&#xff0c;子级选中后没有打勾显示 排查 一直以为是这个树形结构和表格不兼容产生的问题&#xff0c;到后来看官方demo都是可以勾选的&#xff0c;最后排查到了版本问题&#xff0c; 项…

电动滑板车UL2272认证测试项目和标准

平衡车ul2272认证标准于2016年2月正式公布&#xff0c;美国消费品安全协会(cpsc)宣布&#xff0c;所有平衡车(包括扭扭车)的制造商、进口商、经销商&#xff0c;其在美国本土生产、进口、销售的平衡车必须符合新的安全标准&#xff0c;包括ul2272平衡车电路系统认证标准。另外&…

flutter开发入门,windows环境安装,耗时一天解决各种bug,终于成功

首先说明要安装的环境&#xff1a;java8必须&#xff0c;android studio&#xff0c;chrome是开发安卓和web是必须的 java8的下载地址&#xff1a;https://www.java.com/en/download/、 java8蓝奏云下载地址&#xff1a;jre-8u381-windows-x64.exe - 蓝奏云 flutter国内环境…