MyBatis 动态 SQL 的详细内容讲解

发布于:2024-06-17 ⋅ 阅读:(17) ⋅ 点赞:(0)

1. MyBatis 动态 SQL 的详细内容讲解


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

在这里插入图片描述

delete from t_car where id in(1,2,3,4,5,6,......这里的值是动态的,根据用户选择的id不同,值是不同的);

多条件查询:

在这里插入图片描述

select * from t_car where brand like '丰田%' and guide_price > 30 and .....;

2. 准备工作

数据表结构的设计,数据表名为:t_car

在这里插入图片描述

t_car 表中的数据信息:

在这里插入图片描述

pom.xml 文件当中配置相关的依赖的 jar 包如下:

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.rainbowsea</groupId>
    <artifactId>mybatis-005-crud-blog</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>

    <dependencies>
        <!--        mybatis 的依赖-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.10</version>
        </dependency>

        <!--        mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.30</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>

        <!--        引入 logback的依赖,这个日志框架实现了slf4j 规范-->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.11</version>
        </dependency>
    </dependencies>

</project>

配置 logback 的配置文件,用于打印显示,我们的日志信息,方便我们查看我们的运行过程,效果。

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>

<configuration debug="false">
    <!-- 控制台输出 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
    </appender>

    <!--mybatis log configure-->
    <logger name="com.apache.ibatis" level="TRACE"/>
    <logger name="java.sql.Connection" level="DEBUG"/>
    <logger name="java.sql.Statement" level="DEBUG"/>
    <logger name="java.sql.PreparedStatement" level="DEBUG"/>

    <!-- 日志输出级别,logback日志级别包括五个:TRACE < DEBUG < INFO < WARN < ERROR -->
    <root level="DEBUG">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="FILE"/>
    </root>

</configuration>

配置 MyBatis 的核心配置文件,

在这里插入图片描述

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

        <!--  使用 <package>	还可以将这个包下的所有的类的全部自动起别名,别名就是简名,不区分大小写 -->
        <package name="com.rainbowsea.mybatis.pojo"/>
    </typeAliases>
    <environments default="mybatis">

        <environment id="mybatis">
            <!--            MANAGED 没有用第三框架管理的话,都是会被提交的,没有事务上的管理了 -->
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="MySQL123"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <!-- 这里也是可以使用 package 包名扫描,但是同样的:对应接口路径要一致,接口名一致-->
        <package name="com.rainbowsea.mybatis.mapper"></package>
    </mappers>
</configuration>

对照 t_car 创建的ORM 映射的 Car 类

注意:在MyBatis 当中对应的ORM ,一般在框架里对应的 Bean实体类,一定要实现该 set 和 get 方法以及无参数构造方法,无法框架无法使用反射机制,进行操作

建议用包装类,这样可以防止 Null的问题,因为(简单类型 int num = null ,是不可以赋值为 null)的编译无法通过

在这里插入图片描述

package com.rainbowsea.mybatis.pojo;

public class Car {
    // 数据库表当中的字段应该和pojo类的属性一一对应
    // 建议使用包装类,这样可以防止null的问题
    private Long id;
    private String carNum;
    private String brand;
    private Double guidePrice;
    private String produceTime;
    private String carType;

    public Car() {
    }

    public Car(Long id, String carNum, String brand, Double guidePrice, String produceTime, String carType) {
        this.id = id;
        this.carNum = carNum;
        this.brand = brand;
        this.guidePrice = guidePrice;
        this.produceTime = produceTime;
        this.carType = carType;
    }

    @Override
    public String toString() {
        return "Car{" +
                "id=" + id +
                ", carNum='" + carNum + '\'' +
                ", brand='" + brand + '\'' +
                ", guidePrice=" + guidePrice +
                ", produceTime='" + produceTime + '\'' +
                ", catType='" + carType + '\'' +
                '}';
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getCarNum() {
        return carNum;
    }

    public void setCarNum(String carNum) {
        this.carNum = carNum;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public Double getGuidePrice() {
        return guidePrice;
    }

    public void setGuidePrice(Double guidePrice) {
        this.guidePrice = guidePrice;
    }

    public String getProduceTime() {
        return produceTime;
    }

    public void setProduceTime(String produceTime) {
        this.produceTime = produceTime;
    }

    public String getcarType() {
        return carType;
    }

    public void setcarType(String catType) {
        this.carType = catType;
    }
}

3. if 标签

需求:多条件查询。

可能的条件包括:品牌(brand)、指导价格(guide_price)、汽车类型(car_type)

多条件查询
不提供查询:0 条件 select * from t_product;
当选择一个条件: select * from t_product where brand=#{brand}
当用户选了多个条件:select * from t_product where 条件1=...and 条件2=..and条件3 =...

 <if test="表达式运行之后的结果是false,不会拼接"></if>

if 标签的使用的注意事项:

  1. if 标签中的 test 属性是必须的
  2. if 标签中 test 属性的值是false 或者 true
  3. 如果test是true ,则if标签中的sql语句就会拼接,反之则部分拼接、
  4. test属性中可以使用的是:
    1. 当使用了@Param注解,那么 test 中给你要出现的是 @Param 注解指定的参数名,@Param(“brand”)
    2. 当没有使用@Param注解,那么test中要出现的是:param1,param2,param3 ; arg0,arg1…
    3. 当使用了POJO,那么test中出现的是POJO类的属性名,
    4. 5.在mybatis的动态SQL当中,不能使用&&,只能使用 and ,or
  5. 注意单引号双引号交替使用

在这里插入图片描述

package com.rainbowsea.mybatis.mapper;

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

import java.util.List;

public interface CarMapper {

    /**
     * 多条件查询
     *
     * @param brand       品牌
     * @param guiderPrice 指导价
     * @param carType     汽车类型
     * @return
     */
    List<Car> selectByMultiCondition(@Param("brand") String brand, @Param("guidePrice") Double guiderPrice,
                                     @Param("carType") String carType);
}

在这里插入图片描述

在这里插入图片描述

<?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">

<!--namespace 一定要是:对应的接口的全限定类名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.CarMapper">

    <!--	id 要是 namespace 对应接口上的方法名: -->
    <select id="selectByMultiCondition" resultType="Car">
        SELECT id, car_num, brand, guide_price, produce_time, car_type
        FROM `t_car`
        where 1=1
        <!--
            1.if标签中的test属性是必须的
            2.if标签中test属性的值是false 或者 true
            3.如果test是true ,则if标签中的sql语句就会拼接,反之则部分拼接
            4.test属性中可以使用的是:
                当使用了@Param注解,那么test中i给你要出现的是@Param注解指定的参数名,@Param("brand")
                当没有使用@Param注解,那么test中要出现的是:param1,param2,param3 ; arg0,arg1...
                当使用了POJO,那么test中出现的是POJO类的属性名
            5.在mybatis的动态SQL当中,不能使用&&,只能使用 and ,or
            6.注意单引号双引号交替使用
        -->
        <!--        <if test="表达式运行之后的结果是false,不会拼接"></if>-->
        <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>
    </select>

</mapper>

运行测试:

在这里插入图片描述

在这里插入图片描述

package com.rainbowsea.mybatis.test;

import com.rainbowsea.mybatis.mapper.CarMapper;
import com.rainbowsea.mybatis.pojo.Car;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.IOException;
import java.util.List;

public class CarMapperTest {


    @Test
    public void testSelectByMultiCondition() throws IOException {
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "mybatis");
        SqlSession sqlSession = sqlSessionFactory.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        // 假设三个条件都不为null
        //List<Car> cars = mapper.selectByMultiCondition("小米",21.00,"新能源");
        // 假设三个条件都是空
        //List<Car> cars = mapper.selectByMultiCondition("",null,"");

        // 假设后两个条件不为空,第一个条件为空
        //List<Car> cars = mapper.selectByMultiCondition("",21.00,"新能源");

        // 假设第一个条件不是空,后两个条件为空
        List<Car> cars = mapper.selectByMultiCondition("小米",null,"");

        cars.forEach(car -> {
            System.out.println(car);
        });


        sqlSession.close();

    }
}

补充:

如果第一个条件为空,剩下两个条件不为空,会是怎样呢?

List<Car> cars = mapper.selectByMultiCondition("", 20.0, "燃油车");

在这里插入图片描述

报错了,SQL语法有问题,where后面出现了and。这该怎么解决呢?

可以where后面添加一个恒成立的条件。

在这里插入图片描述

在这里插入图片描述

4. where 标签

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

  • 所有条件都为空时,where 标签不会生成where子句。同时满足条件 会自动生成 where 关键字,不需要我们手动添加。
  • 自动去除某些条件前面多余的 and 或 or。

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

需求:多条件查询。

可能的条件包括:品牌(brand)、指导价格(guide_price)、汽车类型(car_type)

在这里插入图片描述

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

import java.util.List;

public interface CarMapper {

    /**
     * 使用where标签,让where 子句更加灵活,更加智能
     *
     * @param brand
     * @param guidePrice
     * @param carType
     * @return
     */
    List<Car> selectByMultiConditionWithWhere(@Param("brand") String brand, @Param("guidePrice") Double guidePrice,
                                              @Param("carType") String carType);
    
}

在这里插入图片描述

<?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">

<!--namespace 一定要是:对应的接口的全限定类名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.CarMapper">

    <select id="selectByMultiConditionWithWhere" resultType="Car">
        SELECT id, car_num, brand, guide_price, produce_time, car_type
        FROM `t_car`
        <!--where 标签是专门负责 where 子句动态生成的,不用我们自己再写 where 关键字了,自动生成-->
        <!--自动去除某些条件前面多余的and或or。-->
        <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>

</mapper>

运行测试:

在这里插入图片描述


import com.rainbowsea.mybatis.mapper.CarMapper;
import com.rainbowsea.mybatis.pojo.Car;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.IOException;
import java.util.List;

public class CarMapperTest {

    @Test
    public void testSelectByMultiConditionWithWhere() throws IOException {
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "mybatis");
        SqlSession sqlSession = sqlSessionFactory.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        // 假设三个条件都不为null
        List<Car> cars = mapper.selectByMultiConditionWithWhere("小米",21.00,"新能源");

        // 如果第一个条件是空,其他的不为空
        List<Car> cars2 = mapper.selectByMultiConditionWithWhere("",21.00,"新能源");


        // 假设第一个条件不是空,后两个条件为空
        List<Car> cars3 = mapper.selectByMultiConditionWithWhere("小米",null,"");

        cars3.forEach(car -> {
            System.out.println(car);
        });


        sqlSession.close();
    }
}

5. trim 标签

trim标签的属性:

  • prefix:在trim标签所有内容的最 前面添加内容
  • suffix:在trim标签中所有内容的最 后面添加 内容
  • prefixOverrides:trim 标签中所有内容当中前缀覆盖掉(去掉)
  • suffixOverrides:trim 标签中所有内容当中后缀覆盖掉(去掉)

在这里插入图片描述

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

import java.util.List;

public interface CarMapper {

    /**
     * 使用 trim 标签,添加删除
     *
     * @param brand
     * @param guidePrice
     * @param carType
     * @return
     */
    List<Car> selectByMultiConditionWithTrim(@Param("brand") String brand, @Param("guidePrice") Double guidePrice,
                                             @Param("carType") String carType);
}

在这里插入图片描述

<?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">

<!--namespace 一定要是:对应的接口的全限定类名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.CarMapper">

    <select id="selectByMultiConditionWithTrim" resultType="Car" >
        SELECT id, car_num, brand, guide_price, produce_time, car_type
        FROM `t_car`
        <!--
            prefix 加前缀
            suffix: 加后缀
            prefixOverriders: 删除前缀
            suffixOverrides : 删除后缀

        prefix="where" 表示是在 trim 标签所有内容的最前面添加 where ,suffix 同理
        suffixOverrides="and|or" 把 trim 标签中所有内容的后缀 and 或 or 去掉
        -->
        <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>

</mapper>

运行测试:

在这里插入图片描述


import com.rainbowsea.mybatis.mapper.CarMapper;
import com.rainbowsea.mybatis.pojo.Car;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.IOException;
import java.util.List;

public class CarMapperTest {

    @Test
    public void testSelectByMultiConditionWithTrim() throws IOException {
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "mybatis");
        SqlSession sqlSession = sqlSessionFactory.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        List<Car> cars = mapper.selectByMultiConditionWithTrim("", null, "");
        List<Car> cars2 = mapper.selectByMultiConditionWithTrim("小米", null, "");

        cars.forEach(car -> {
            System.out.println(car);
        });


        sqlSession.close();
    }
}

6. set 标签

主要使用在 update 语句当中,用来生成 set 关键字,同时去掉最后多余的“,”。set 标签会自动添加 set 关键字,不用我们自己再写了-

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

在这里插入图片描述


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

import java.util.List;

public interface CarMapper {

    /**
     * 使用set 标签
     *
     * @param car
     * @return
     */
    int updateSet(Car car);

}

在这里插入图片描述

<?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">

<!--namespace 一定要是:对应的接口的全限定类名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.CarMapper">

    <update id="updateSet">
        update t_car
        <!--set 标签会自动添加 set 关键字,不用我们自己再写了-->
        <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>
</mapper>

运行测试:

将 id 为 128的 brand 改为:丰田霸道 ,car_type 改为 燃油车,其他的为 null (这里使用了 set ,为null / 空字段值,不会被修改)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


import com.rainbowsea.mybatis.mapper.CarMapper;
import com.rainbowsea.mybatis.pojo.Car;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.IOException;
import java.util.List;

public class CarMapperTest {

    /*
       * 主要使用在update语句当中,用来生成set关键字,同时去掉最后多余的“,”
   比如我们只更新提交的不为空的字段,如果提交的数据是空或者"",那么这个字段我们将不更新。*/
    @Test
    public void testUpdateSet() throws IOException {
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "mybatis");
        SqlSession sqlSession = sqlSessionFactory.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        Car car = new Car(128L, null, "丰田霸道", null, null, "燃油车");
        mapper.updateSet(car);
        sqlSession.commit();
        sqlSession.close();
    }
}

7. choose when otherwise 标签

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

<choose>
  <when></when>
  <when></when>
  <when></when>
  <otherwise></otherwise>  // 上面的 when 都没满足时,执行这个
</choose>

等同于

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

}

只有一个分支会被选择(其中一个满足了,后面的就不会进去了),被执行 SQL拼接 !!!!

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

在这里插入图片描述

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

import java.util.List;

public interface CarMapper {
    /**
     * 使用choose when otherwise 标签
     *
     * @param brand
     * @param guiderPrice
     * @param carType
     * @return
     */
    List<Car> selectByChoose(@Param("brand") String brand, @Param("guidePrice") Double guiderPrice,
                             @Param("carType") String carType);

}

在这里插入图片描述

<?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">

<!--namespace 一定要是:对应的接口的全限定类名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.CarMapper">

    <select id="selectByChoose" resultType="Car">
        SELECT id, car_num, brand, guide_price, produce_time, car_type
        FROM `t_car`
            <!--只会执行其中的 一个满足条件的分支当中。-->
        <where>
            <choose>
            <!-- 当其中的某个 when 满足条件,进入该 when 的SQL语句(拼接),并执行,后面其他的when 就不会进入了-->
                <when test="brand != null and brand != ''">
                    brand like "%"#{brand}"%"
                </when>
                <when test="guidePrice != null and guidePrice !=''">
                    guide_price > #{guidePrice}
                </when>
                <otherwise>
                    <!-- 当上面所有的 when 都没有满足条件的,则会进入这里的 otherwise的SQL语句(拼接),并执行-->
                    car_type = #{carType}
                </otherwise>
            </choose>
        </where>
    </select>

</mapper>

运行测试:

在这里插入图片描述

在这里插入图片描述


import com.rainbowsea.mybatis.mapper.CarMapper;
import com.rainbowsea.mybatis.pojo.Car;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.IOException;
import java.util.List;

public class CarMapperTest {

    /**
     * 只有一个分支会被选择!!!!
     */
    @Test
    public void testSelectByChoose() throws IOException {
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "mybatis");
        SqlSession sqlSession = sqlSessionFactory.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        // 三个条件不为空
        List<Car> cars = mapper.selectByChoose("丰田霸道",3.00,"燃油车");
        // 第一条件为空
        List<Car> cars2 = mapper.selectByChoose("",3.00,"燃油车");
        // 两个条件为Null
        List<Car> cars3 = mapper.selectByChoose("",null,"燃油车");
        // 全部为空,执行选择 otherwise 标签当中的信息
        List<Car> cars4 = mapper.selectByChoose("",null,"");
        cars4.forEach(car ->{
            System.out.println(car);
        });

        sqlSession.close();
    }
}

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

8.1 批量删除

方式一:

delete from t_car where id in(1,2,3);

在这里插入图片描述

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

import java.util.List;

public interface CarMapper {

    /**
     * 批量删除,foreach 标签
     *
     * @param ids
     * @return
     */
    int deleteByIds(@Param("ids") Long[] ids);
}

foreach 标签的属性:

 collection :指定数组或者集合,在对应接口方法当中参数中定义的参数名
        item:代表数组或集合中的元素的一个临时变量,命名随意,但是最好见名知意
        separator:循环之间的分隔符
        open: foreach 循环拼接的所有sql语句的最前面以什么开始
        close: foreach 循环拼接的所有sql语句的最前面以什么结束

        collection="ids" 第一次写这个的时候报错了,
            错误信息是:{array,arg0}什么意思?
            map.put("array",数组)
            map.put("arg0",数组)
 <!--  delete from t_car where id in(1,2,3)-->
        <!-- delete from t_car where id in ( -->
<foreach collection="ids" item="变量" separator=",">
</foreach>


<foreach collection="ids" item="aaa" separator=",">
             #{aaa}
 </foreach>

在这里插入图片描述

在这里插入图片描述

<?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">

<!--namespace 一定要是:对应的接口的全限定类名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.CarMapper">

    <!--
           foreach 标签的属性:
           collection :指定数组或者集合,在对应接口方法当中参数中定义的参数名
           item:代表数组或集合中的元素
           separator:循环之间的分隔符
           open: foreach 循环拼接的所有sql语句的最前面以什么开始
           close: foreach 循环拼接的所有sql语句的最前面以什么结束

           collection="ids" 第一次写这个的时候报错了,错误西悉尼是:{array,arg0}
           什么意思?
               map.put("array",数组)
               map.put("arg0",数组)
   -->
    <delete id="deleteByIds">
        <!--  delete from t_car where id in(1,2,3)-->
        <!-- delete from t_car where id in ( -->
        <!--<foreach collection="ids" item="变量" separator=","></foreach>-->
        <!-- <foreach collection="ids" item="aaa" separator=",">
             #{aaa}
         </foreach>-->

        <!-- ) -->
        delete from t_car where id in
        <foreach collection="ids" item="id" separator="," open="(" close=")">
            #{id}
        </foreach>
    </delete>

</mapper>

运行测试:

在这里插入图片描述

方式二:

delete from t_car where id = 1 or id = 2 or id = 3;

在这里插入图片描述

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

import java.util.List;

public interface CarMapper {

    /**
     * 批量删除第二种方式 or
     *
     * @param ids
     * @return
     */
    int deleteByIds2(@Param("ids") Long[] ids);

}

在这里插入图片描述

<?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">

<!--namespace 一定要是:对应的接口的全限定类名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.CarMapper">
    <delete id="deleteByIds2">
        delete from t_car where
        <foreach collection="ids" separator="or" item="id">
            id=#{id}
        </foreach>
    </delete>
</mapper>

运行测试:

删除id为 136 ,137 两条记录

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


import com.rainbowsea.mybatis.mapper.CarMapper;
import com.rainbowsea.mybatis.pojo.Car;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class CarMapperTest {
    @Test
    public void testDeleteByIds2() throws IOException {
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "mybatis");
        SqlSession sqlSession = sqlSessionFactory.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        Long[] ids = {136L, 137L};
        mapper.deleteByIds2(ids);
        sqlSession.commit();
        sqlSession.close();
    }
}

8.2 批量添加

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

在这里插入图片描述

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

import java.util.List;

public interface CarMapper {
    /**
     * 批量插入,一次插入多个Car信息
     *
     * @param cars
     * @return
     */
    int insertBath(@Param("cars") List<Car> cars);

}

需要注意的是:这里是封装到POJO实体类当中的,所定义的 item的变量后,所有POJO实体类的属性名,用 "." 的方式,比如:car.carNum,变量名.POJO实体类的属性名

在这里插入图片描述

<?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">

<!--namespace 一定要是:对应的接口的全限定类名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.CarMapper">

    <insert id="insertBath">
        insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values
        <foreach collection="cars" item="car" separator=",">
            <!--需要注意的是:这里是封装到POJO实体类当中的,所定义的 item的变量后,所有POJO实体类的属性名,用 "."的方式-->
            (null,#{car.carNum},#{car.brand},#{car.guidePrice},#{car.produceTime},#{car.carType})
        </foreach>

    </insert>
</mapper>

运行测试:

在这里插入图片描述

在这里插入图片描述


import com.rainbowsea.mybatis.mapper.CarMapper;
import com.rainbowsea.mybatis.pojo.Car;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class CarMapperTest {
    @Test
    public void testInsertBath() throws IOException {
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "mybatis");
        SqlSession sqlSession = sqlSessionFactory.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);

        Car car1 = new Car(null, "1201", "玛莎拉蒂1", 30.0, "2020-12", "燃油车");
        Car car2 = new Car(null, "1202", "玛莎拉蒂2", 30.0, "2020-12", "燃油车");
        Car car3 = new Car(null, "1203", "玛莎拉蒂3", 30.0, "2020-12", "燃油车");
        List<Car> cars = new ArrayList<>();
        cars.add(car1);
        cars.add(car2);
        cars.add(car3);
        mapper.insertBath(cars);
        sqlSession.commit();
        sqlSession.close();
    }

}

9. SQL 标签与 include 标签

sql标签用来声明sql片段

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

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

首先就是通过 <SQL> 标签定义/声明一个SQL片段,再通过 <include> 标签根据所声明的 SQL语句片段的 id ,引用相关SQL片段的内容。

在这里插入图片描述

<?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">

<!--namespace 一定要是:对应的接口的全限定类名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.CarMapper">

    

    <!--    声明一个sql片段-->
    <sql id="carColumnNameSql">
        id
        ,
        car_num      as carNum,
        brand,
        guide_price  as guidePrice,
        produce_time as produceTime,
        car_type     as carType

    </sql>
    <select id="selectById2" resultType="Car">
        SELECT
        <!--将声明的sql片段包含进来-->
        <include refid="carColumnNameSql"></include>
        FROM `t_car`
        where id=#{id}
    </select>

</mapper>

运行测试:

在这里插入图片描述

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

import java.util.List;

public interface CarMapper {

    /**
     * 测试 sql标签,代码片段的运用
     *
     * @param id
     * @return
     */
    Car selectById2(@Param("id") Long id);

}

在这里插入图片描述

在这里插入图片描述

import com.rainbowsea.mybatis.mapper.CarMapper;
import com.rainbowsea.mybatis.pojo.Car;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class CarMapperTest {

    @Test
    public void testSelectById2() throws IOException {
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "mybatis");
        SqlSession sqlSession = sqlSessionFactory.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        Car car = mapper.selectById2(118L);
        System.out.println(car);
        sqlSession.close();
    }
}

10. 总结:

  1. if 标签: if 标签中的 test 属性是必须的,if 标签中 test 属性的值是false 或者 true,如果test是true ,则if标签中的sql语句就会拼接,反之则部分拼接、
  2. Where标签:所有条件都为空时,where 标签不会生成where子句。同时满足条件 会自动生成 where 关键字,不需要我们手动添加。自动去除某些条件前面多余的 and 或 or。
  3. trim 标签:
- prefix:在trim标签所有内容的最 前面添加内容
- suffix:在trim标签中所有内容的最  后面添加 内容
- prefixOverrides:trim 标签中所有内容当中前缀覆盖掉(去掉)
- suffixOverrides:trim 标签中所有内容当中后缀覆盖掉(去掉

  1. set 标签:主要使用在 update 语句当中,用来生成 set 关键字,同时去掉最后多余的“,”。set 标签会自动添加 set 关键字,不用我们自己再写了-

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

  2. choose when otherwise 标签:这三个标签是在一起使用的:

    <choose>
      <when></when>
      <when></when>
      <when></when>
      <otherwise></otherwise>  // 上面的 when 都没满足时,执行这个
    </choose>
    

    等同于

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

    只有一个分支会被选择(其中一个满足了,后面的就不会进去了),被执行 SQL拼接 !!!!

  3. SQL标签与 include 标签:提高代码的复用性。首先就是通过 <SQL> 标签定义/声明一个SQL片段,再通过 <include> 标签根据所声明的 SQL语句片段的 id ,引用相关SQL片段的内容。

11. 最后:

“在这个最后的篇章中,我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉,我从你们身上吸取了无尽的灵感与勇气。我会将你们的鼓励留在心底,继续在其他的领域奋斗。感谢你们,我们总会在某个时刻再次相遇。”

在这里插入图片描述