MyBatis学习笔记——3

MyBatis学习笔记——3

  • 一、MyBatis小技巧
    • 1.1、#{}和${}
    • 1.2、typeAliases
    • 1.3、mappers
    • 1.4、插入数据时获取自动生成的主键
  • 二、MyBatis参数处理
    • 2.1、单个简单类型参数
    • 2.2、 Map参数
    • 2.3、实体类参数
    • 2.4、多参数
    • 2.5、 @Param注解(命名参数)
    • 2.6、 @Param源码分析
  • 三、MyBatis查询语句专题
    • 3.1、返回Car
    • 3.2、返回List
    • 3.3、返回Map
    • 3.4、返回List
    • 3.5、返回Map
    • 3.6、resultMap结果映射
    • 3.7、返回总记录条数
  • 四、动态SQL
    • 4.1、if标签
    • 4.2、Where标签
    • 4.3、trim标签
    • 4.4、set标签
    • 4.5、choose when otherwise
    • 4.6、foreach标签
      • 4.6.1、批量删除
      • 4.6.2、批量增加
    • 4.7、sql标签与include标签

一、MyBatis小技巧

1.1、#{}和${}

#{}:先编译sql语句,再给占位符传值,底层是PreparedStatement实现。可以防止sql注入,比较常用

  • 使用该方法会自动给传入的值添加''

${}:先进行sql语句拼接,然后再编译sql语句,底层是Statement实现。存在sql注入现象。只有在需要进行sql语句关键字拼接的情况下才会用到

  • 比如在书写升降序查询功能的SQL时,就需要使用${}来时asc或desc不带''形式拼接到SQL语句中

    select id,car_num as carNum,brand,guide_price as guidePrice,produce_time as produceTime,car_type as carType from t_car order by carNum 'desc'

    desc是一个关键字,不能带单引号的,所以在进行sql语句关键字拼接的时候,必须使用${}

模糊查询

需求:查询奔驰系列的汽车。【只要品牌brand中含有奔驰两个字的都查询出来。】

使用${}

CarMapper接口

List<Car> selectLikeByBrand(String likeBrank);

CarMapper.xml

<select id="selectLikeByBrand" 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>

CarMapperTest.testSelectLikeByBrand

@Test
public void testSelectLikeByBrand(){
    CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    List<Car> cars = mapper.selectLikeByBrand("奔驰");
    cars.forEach(car -> System.out.println(car));
}

MyBatis学习笔记——3_第1张图片

使用#{}

第一种:concat函数

<select id="selectLikeByBrand" 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 concat('%',#{brand},'%')
select>

第二种:双引号方式

<select id="selectLikeByBrand" 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>

1.2、typeAliases

第一种方式:typeAlias

<typeAliases>
  <typeAlias type="com.powernode.mybatis.pojo.Car" alias="Car"/>
typeAliases>
  • 首先要注意typeAliases标签的放置位置,如果不清楚的话,可以看看错误提示信息。
  • typeAliases标签中的typeAlias可以写多个。
  • typeAlias:
  • type属性:指定给哪个类起别名
  • alias属性:别名。
    + alias属性不是必须的,如果缺省的话,type属性指定的类型名的简类名作为别名。
    + alias是大小写不敏感的。也就是说假设alias=“Car”,再用的时候,可以CAR,也可以car,也可以Car,都行。

第二种方式:package

如果一个包下的类太多,每个类都要起别名,会导致typeAlias标签配置较多,所以mybatis用提供package的配置方式,只需要指定包名,该包下的所有类都自动起别名,别名就是简类名。并且别名不区分大小写。

<typeAliases>
  <package name="com.powernode.mybatis.pojo"/>
typeAliases>

package也可以配置多个的。

1.3、mappers

SQL映射文件的配置方式包括四种:

  • resource:从类路径中加载
  • url:从指定的全限定资源路径中加载
  • class:使用映射器接口实现类的完全限定类名
  • package:将包内的映射器接口实现全部注册为映射器

resource
这种方式是从类路径中加载配置文件,所以这种方式要求SQL映射文件必须放在resources目录下或其子目录下。

<mappers>
  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
  <mapper resource="org/mybatis/builder/BlogMapper.xml"/>
  <mapper resource="org/mybatis/builder/PostMapper.xml"/>
mappers>

url
这种方式显然使用了绝对路径的方式,这种配置对SQL映射文件存放的位置没有要求,随意。

<mappers>
  <mapper url="file:///var/mappers/AuthorMapper.xml"/>
  <mapper url="file:///var/mappers/BlogMapper.xml"/>
  <mapper url="file:///var/mappers/PostMapper.xml"/>
mappers>

class
如果使用这种方式必须满足以下条件:

  • SQL映射文件和mapper接口放在同一个目录下。
  • SQL映射文件的名字也必须和mapper接口名一致。

<mappers>
  <mapper class="org.mybatis.builder.AuthorMapper"/>
  <mapper class="org.mybatis.builder.BlogMapper"/>
  <mapper class="org.mybatis.builder.PostMapper"/>
mappers>

将CarMapper.xml文件移动到和mapper接口同一个目录下:

  • 在resources目录下新建:com/powernode/mybatis/mapper【这里千万要注意:不能这样新建 com.powernode.mybatis.dao
  • 将CarMapper.xml文件移动到mapper目录下
  • 修改mybatis-config.xml文件
<mappers>
  <mapper class="com.powernode.mybatis.mapper.CarMapper"/>
mappers>

package

如果class较多,可以使用这种package的方式,但前提条件和上一种方式一样。


<mappers>
  <package name="com.powernode.mybatis.mapper"/>
mappers>

1.4、插入数据时获取自动生成的主键

前提是:主键是自动生成的。
业务背景:一个用户有多个角色。
MyBatis学习笔记——3_第2张图片
插入一条新的记录之后,自动生成了主键,而这个主键需要在其他表中使用时。
插入一个用户数据的同时需要给该用户分配角色:需要将生成的用户的id插入到角色表的user_id字段上。

第一种方式:可以先插入用户数据,再写一条查询语句获取id,然后再插入user_id字段。【比较麻烦】
第二种方式:mybatis提供了一种方式更加便捷。

CarMapper接口

/**
     * 获取自动生成的主键
     * @param car
     */
void insertUseGeneratedKeys(Car car);

CarMapper.xml

<insert id="insertUseGeneratedKeys" useGeneratedKeys="true" keyProperty="id">
  insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})
insert>

CarMapperTest.testInsertUseGeneratedKeys

@Test
public void testInsertUseGeneratedKeys(){
    CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    Car car = new Car();
    car.setCarNum("5262");
    car.setBrand("BYD汉");
    car.setGuidePrice(30.3);
    car.setProduceTime("2020-10-11");
    car.setCarType("新能源");
    mapper.insertUseGeneratedKeys(car);
    SqlSessionUtil.openSession().commit();
    System.out.println(car.getId());
}

二、MyBatis参数处理

2.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:可以省略

2.2、 Map参数

需求:根据name和age查询

StudentMapper接口

/**
* 根据name和age查询
* @param paramMap
* @return
*/
List<Student> selectByParamMap(Map<String,Object> paramMap);

StudentMapperTest.testSelectByParamMap

@Test
public void testSelectByParamMap(){
    // 准备Map
    Map<String,Object> paramMap = new HashMap<>();
    paramMap.put("nameKey", "张三");
    paramMap.put("ageKey", 20);

    List<Student> students = mapper.selectByParamMap(paramMap);
    students.forEach(student -> System.out.println(student));
}

StudentMapper.xml

<select id="selectByParamMap" resultType="student">
  select * from t_student where name = #{nameKey} and age = #{ageKey}
select>

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

2.3、实体类参数

需求:插入一条Student数据
StudentMapper接口

/**
 * 保存学生数据
 * @param student
 * @return
 */
int insert(Student student);

StudentMapper.xml

<insert id="insert">
  insert into t_student values(null,#{name},#{age},#{height},#{birth},#{sex})
insert>

StudentMapperTest.testInsert

@Test
public void testInsert(){
    Student student = new Student();
    student.setName("李四");
    student.setAge(30);
    student.setHeight(1.70);
    student.setSex('男');
    student.setBirth(new Date());
    int count = mapper.insert(student);
    SqlSessionUtil.openSession().commit();
}

运行正常,数据库中成功添加一条数据。
这里需要注意的是:#{} 里面写的是属性名字。这个属性名其本质上是:set/get方法名去掉set/get之后的名字。

2.4、多参数

通过name和sex查询
StudentMapper接口

    /**
     * 根据name和sex查询
     * @param name
     * @param sex
     * @return
     */
    List<Student> selectByNameAndSex(String name, Character sex);

StudentMapperTest.testSelectByNameAndSex

@Test
public void testSelectByNameAndSex(){
    List<Student> students = mapper.selectByNameAndSex("张三", '女');
    students.forEach(student -> System.out.println(student));
}

StudentMapper.xml

<select id="selectByNameAndSex" resultType="student">
  select * from t_student where name = #{name} and sex = #{sex}
select>

在这里插入图片描述
异常信息描述了:name参数找不到,可用的参数包括[arg1, arg0, param1, param2]
修改StudentMapper.xml配置文件:尝试使用[arg1, arg0, param1, param2]去参数

StudentMapper.xml

<select id="selectByNameAndSex" resultType="student">
  
  select * from t_student where name = #{arg0} and sex = #{arg1}
select>

再次尝试修改StudentMapper.xml文件

<select id="selectByNameAndSex" resultType="student">
  
  
  
  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}这种形式。

2.5、 @Param注解(命名参数)

可以不用arg0 arg1 param1 param2吗?这个map集合的key我们自定义可以吗?当然可以。使用@Param注解即可。这样可以增强可读性。
需求:根据name和age查询

    /**
     * 根据name和age查询
     * @param name
     * @param age
     * @return
     */
    List<Student> selectByNameAndAge(@Param(value="name") String name, @Param("age") int age);
    @Test
    public void testSelectByNameAndAge(){
        List<Student> stus = mapper.selectByNameAndAge("张三", 20);
        stus.forEach(student -> System.out.println(student));
    }
<select id="selectByNameAndAge" resultType="student">
  select * from t_student where name = #{name} and age = #{age}
select>

通过测试,一切正常。

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

2.6、 @Param源码分析

MyBatis学习笔记——3_第3张图片

三、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

3.1、返回Car

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

package com.powernode.mybatis.mapper;

import com.powernode.mybatis.pojo.Car;
public interface CarMapper {

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


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 carNum,brand,guide_price guidePrice,produce_time produceTime,car_type carType from t_car where id = #{id}
    select>
mapper>
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.junit.Test;

public class CarMapperTest {

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

查询结果是一条的话也可以使用List集合接收

3.2、返回List

当查询的记录条数是多条的时候,必须使用集合接收。如果使用单个实体类接收会出现异常。

/**
* 查询所有的Car
* @return
*/
List<Car> selectAll();
<select id="selectAll" resultType="Car">
  select id,car_num carNum,brand,guide_price guidePrice,produce_time produceTime,car_type carType from t_car
select>
@Test
public void testSelectAll(){
    CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    List<Car> cars = mapper.selectAll();
    cars.forEach(car -> System.out.println(car));
}

MyBatis学习笔记——3_第4张图片

如果返回多条记录,采用单个实体类接收会怎样?

/**
* 查询多条记录,采用单个实体类接收会怎样?
* @return
*/
Car selectAll2();
<select id="selectAll2" resultType="Car">
  select id,car_num carNum,brand,guide_price guidePrice,produce_time produceTime,car_type carType from t_car
select>
@Test
public void testSelectAll2(){
    CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    Car car = mapper.selectAll2();
    System.out.println(car);
}

MyBatis学习笔记——3_第5张图片

3.3、返回Map

当返回的数据,没有合适的实体类对应的话,可以采用Map集合接收。字段名做key,字段值做value。
查询如果可以保证只有一条数据,则返回一个Map集合即可。

MyBatis学习笔记——3_第6张图片

/**
 * 通过id查询一条记录,返回Map集合
 * @param id
 * @return
 */
Map<String, Object> selectByIdRetMap(Long id);
<select id="selectByIdRetMap" resultType="map">
  select id,car_num carNum,brand,guide_price guidePrice,produce_time produceTime,car_type carType from t_car where id = #{id}
select>

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

@Test
public void testSelectByIdRetMap(){
    CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    Map<String,Object> car = mapper.selectByIdRetMap(35L);
    System.out.println(car);
}

MyBatis学习笔记——3_第7张图片

当然,如果返回一个Map集合,可以将Map集合放到List集合中吗?当然可以,这里就不再测试了。
反过来,如果返回的不是一条记录,是多条记录的话,只采用单个Map集合接收,这样同样会出现之前的异常:TooManyResultsException

3.4、返回List

查询结果条数大于等于1条数据,则可以返回一个存储Map集合的List集合。List等同于List
MyBatis学习笔记——3_第8张图片

/**
     * 查询所有的Car,返回一个List集合。List集合中存储的是Map集合。
     * @return
     */
List<Map<String,Object>> selectAllRetListMap();
<select id="selectAllRetListMap" resultType="map">
  select id,car_num carNum,brand,guide_price guidePrice,produce_time produceTime,car_type carType from t_car
select>
@Test
public void testSelectAllRetListMap(){
    CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    List<Map<String,Object>> cars = mapper.selectAllRetListMap();
    System.out.println(cars);
}
[
  {carType=燃油车, carNum=103, guidePrice=50.30, produceTime=2020-10-01, id=33, brand=奔驰E300L}, 
  {carType=电车, carNum=102, guidePrice=30.23, produceTime=2018-09-10, id=34, brand=比亚迪汉}, 
  {carType=燃油车, carNum=103, guidePrice=50.30, produceTime=2020-10-01, id=35, brand=奔驰E300L}, 
  {carType=燃油车, carNum=103, guidePrice=33.23, produceTime=2020-10-11, id=36, brand=奔驰C200},
  ......
]

3.5、返回Map

拿Car的id做key,以后取出对应的Map集合时更方便。
MyBatis学习笔记——3_第9张图片

/**
     * 获取所有的Car,返回一个Map集合。
     * Map集合的key是Car的id。
     * Map集合的value是对应Car。
     * @return
     */
@MapKey("id")
Map<Long,Map<String,Object>> selectAllRetMap();
<select id="selectAllRetMap" resultType="map">
  select id,car_num carNum,brand,guide_price guidePrice,produce_time produceTime,car_type carType from t_car
select>
@Test
public void testSelectAllRetMap(){
    CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    Map<Long,Map<String,Object>> cars = mapper.selectAllRetMap();
    System.out.println(cars);
}

执行结果:

{
64={carType=燃油车, carNum=133, guidePrice=50.30, produceTime=2020-01-10, id=64, brand=丰田霸道}, 
66={carType=燃油车, carNum=133, guidePrice=50.30, produceTime=2020-01-10, id=66, brand=丰田霸道}, 
67={carType=燃油车, carNum=133, guidePrice=50.30, produceTime=2020-01-10, id=67, brand=丰田霸道}, 
69={carType=燃油车, carNum=133, guidePrice=50.30, produceTime=2020-01-10, id=69, brand=丰田霸道},
......
}

3.6、resultMap结果映射

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

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

使用resultMap进行结果映射

/**
     * 查询所有Car,使用resultMap进行结果映射
     * @return
     */
List<Car> selectAllByResultMap();

<resultMap id="carResultMap" type="car">
  
  <id property="id" column="id"/>
  <result property="carNum" column="car_num"/>
  
  
  <result property="brand" column="brand" javaType="string" jdbcType="VARCHAR"/>
  <result property="guidePrice" column="guide_price"/>
  <result property="produceTime" column="produce_time"/>
  <result property="carType" column="car_type"/>
resultMap>


<select id="selectAllByResultMap" resultMap="carResultMap">
  select * from t_car
select>
@Test
public void testSelectAllByResultMap(){
    CarMapper carMapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    List<Car> cars = carMapper.selectAllByResultMap();
    System.out.println(cars);
}

执行结果正常。

是否开启驼峰命名自动映射

使用这种方式的前提是:属性名遵循Java的命名规范,数据库表的列名遵循SQL的命名规范。
Java命名规范:首字母小写,后面每个单词首字母大写,遵循驼峰命名方式。
SQL命名规范:全部小写,单词之间采用下划线分割。

比如以下的对应关系:

实体类中的属性名 数据库表的别名
carNum car_num
carType car_type
produceTime produce_time

如何启用该功能,在mybatis-config.xml文件中进行配置:


<settings>
  <setting name="mapUnderscoreToCamelCase" value="true"/>
settings>
/**
* 查询所有Car,启用驼峰命名自动映射
* @return
*/
List<Car> selectAllByMapUnderscoreToCamelCase();
<select id="selectAllByMapUnderscoreToCamelCase" resultType="Car">
  select * from t_car
select>
@Test
public void testSelectAllByMapUnderscoreToCamelCase(){
    CarMapper carMapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    List<Car> cars = carMapper.selectAllByMapUnderscoreToCamelCase();
    System.out.println(cars);
}

执行结果正常。

3.7、返回总记录条数

需求:查询总记录条数

/**
     * 获取总记录条数
     * @return
     */
Long selectTotal();

<select id="selectTotal" resultType="long">
  select count(*) from t_car
select>
@Test
public void testSelectTotal(){
    CarMapper carMapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    Long total = carMapper.selectTotal();
    System.out.println(total);
}

在这里插入图片描述

四、动态SQL

4.1、if标签

  1. if标签中test属性是必须的。
  2. if标签中test属性的值是false或者true
  3. 如果testtrue,则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

DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.Smulll.Mapper.CarMapper">
    <select id="selectByMultiConditional" 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>

4.2、Where标签

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

  • 所有条件都为空时,where标签保证不会生成where子句。
  • 自动去除某些条件前面多余的andor。后面的无法去除

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

<select id="selectByMultiConditionWithWhere" resultType="car">
  select * from t_car
  <where>
    <if test="brand != null and brand != ''">
      and 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>
select>

4.3、trim标签

trim标签的属性:

  • prefix:在trim标签中的语句前添加内容
  • suffix:在trim标签中的语句后添加内容
  • prefixOverrides:前缀覆盖掉(去掉)
  • suffixOverrides:后缀覆盖掉(去掉)
<select id="selectByMultiConditionWithTrim" resultType="car">
  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>

4.4、set标签

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

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

/**
* 更新信息,使用set标签
* @param car
* @return
*/
int updateWithSet(Car car);
<update id="updateWithSet">
  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 testUpdateWithSet(){
    CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    Car car = new Car(38L,"1001","丰田霸道2",10.0,"",null);
    int count = mapper.updateWithSet(car);
    System.out.println(count);
    SqlSessionUtil.openSession().commit();
}

4.5、choose 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 produceTime
* @return
*/
List<Car> selectWithChoose(@Param("brand") String brand, @Param("guidePrice") Double guidePrice, @Param("produceTime") String produceTime);
<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>
        produce_time >= #{produceTime}
      otherwise>
    choose>
  where>
select>
@Test
public void testSelectWithChoose(){
    CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    //List cars = mapper.selectWithChoose("丰田霸道", 20.0, "2000-10-10"); 根据第一个查询
    //List cars = mapper.selectWithChoose("", 20.0, "2000-10-10");	根据第二个查询
    //List cars = mapper.selectWithChoose("", null, "2000-10-10");	根据第三个查询
    List<Car> cars = mapper.selectWithChoose("", null, "");	// 根据第三个查询
    System.out.println(cars);
}

4.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','新能源')

4.6.1、批量删除

  • 用in来删除

属性:
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(){
    CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    int count = mapper.deleteBatchByForeach(new Long[]{40L, 41L, 42L});
    System.out.println("删除了几条记录:" + count);
    SqlSessionUtil.openSession().commit();
}
  • 用or来删除
/**
* 通过foreach完成批量删除
* @param ids
* @return
*/
int deleteBatchByForeach2(@Param("ids") Long[] ids);
<delete id="deleteBatchByForeach2">
  delete from t_car where
  <foreach collection="ids" item="id" separator="or">
    id = #{id}
  foreach>
delete>
@Test
public void testDeleteBatchByForeach2(){
    CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    int count = mapper.deleteBatchByForeach2(new Long[]{40L, 41L, 42L});
    System.out.println("删除了几条记录:" + count);
    SqlSessionUtil.openSession().commit();
}

4.6.2、批量增加

/**
* 批量添加,使用foreach标签
* @param cars
* @return
*/
int insertBatchByForeach(@Param("cars") List<Car> cars);
<insert id="insertBatchByForeach">
  insert into t_car values 
  <foreach collection="cars" item="car" separator=",">
    (null,#{car.carNum},#{car.brand},#{car.guidePrice},#{car.produceTime},#{car.carType})
  foreach>
insert>
@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.insertBatchByForeach(cars);
    System.out.println("插入了几条记录" + count);
    SqlSessionUtil.openSession().commit();
}

4.7、sql标签与include标签

sql标签用来声明sql片段

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

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

<sql id="carCols">id,car_num carNum,brand,guide_price guidePrice,produce_time produceTime,car_type carTypesql>

<select id="selectAllRetMap" resultType="map">
  select <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>

你可能感兴趣的:(SSM框架,mybatis,学习,笔记)