1. MyBatis 动态 SQL 的详细内容讲解
文章目录
- 1. MyBatis 动态 SQL 的详细内容讲解
- 2. 准备工作
- 3. if 标签
- 4. where 标签
- 5. trim 标签
- 6. set 标签
- 7. choose when otherwise 标签
- 8. foreach 标签
- 8.1 批量删除
- 8.2 批量添加
- 9. SQL 标签与 include 标签
- 10. 总结:
- 11. 最后:
有的业务场景,也需要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 标签的使用的注意事项:
- if 标签中的 test 属性是必须的
- if 标签中 test 属性的值是false 或者 true
- 如果test是true ,则if标签中的sql语句就会拼接,反之则部分拼接、
- test属性中可以使用的是:
- 当使用了@Param注解,那么 test 中给你要出现的是 @Param 注解指定的参数名,@Param(“brand”)
- 当没有使用@Param注解,那么test中要出现的是:param1,param2,param3 ; arg0,arg1…
- 当使用了POJO,那么test中出现的是POJO类的属性名,
- 5.在mybatis的动态SQL当中,不能使用&&,只能使用 and ,or
- 注意单引号双引号交替使用
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. 总结:
- if 标签: if 标签中的 test 属性是必须的,if 标签中 test 属性的值是false 或者 true,如果test是true ,则if标签中的sql语句就会拼接,反之则部分拼接、
- Where标签:所有条件都为空时,where 标签不会生成where子句。同时满足条件 会自动生成 where 关键字,不需要我们手动添加。自动去除某些条件前面多余的 and 或 or。
- trim 标签:
- prefix:在trim标签所有内容的最 前面添加内容 - suffix:在trim标签中所有内容的最 后面添加 内容 - prefixOverrides:trim 标签中所有内容当中前缀覆盖掉(去掉) - suffixOverrides:trim 标签中所有内容当中后缀覆盖掉(去掉
set 标签:主要使用在 update 语句当中,用来生成 set 关键字,同时去掉最后多余的“,”。set 标签会自动添加 set 关键字,不用我们自己再写了-
比如我们只更新提交的不为空的字段,如果提交的数据是空或者 “”,那么这个字段我们将不更新。
choose when otherwise 标签:这三个标签是在一起使用的:
<choose> <when></when> <when></when> <when></when> <otherwise></otherwise> // 上面的 when 都没满足时,执行这个 </choose>
等同于
if(){ }else if(){ }else if(){ }else if(){ }else{ }
只有一个分支会被选择(其中一个满足了,后面的就不会进去了),被执行 SQL拼接 !!!!
SQL标签与 include 标签:提高代码的复用性。首先就是通过 <SQL> 标签定义/声明一个SQL片段,再通过 <include> 标签根据所声明的 SQL语句片段的 id ,引用相关SQL片段的内容。
11. 最后:
“在这个最后的篇章中,我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉,我从你们身上吸取了无尽的灵感与勇气。我会将你们的鼓励留在心底,继续在其他的领域奋斗。感谢你们,我们总会在某个时刻再次相遇。”