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 configurationPUBLIC "-//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;}@Overridepublic 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 mapperPUBLIC "-//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_typeFROM `t_car`where 1=1<!--1.if标签中的test属性是必须的2.if标签中test属性的值是false 或者 true3.如果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 ,or6.注意单引号双引号交替使用--><!-- <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 {@Testpublic 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 mapperPUBLIC "-//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_typeFROM `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 {@Testpublic 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);// 假设三个条件都不为nullList<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 mapperPUBLIC "-//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_typeFROM `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 {@Testpublic 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 mapperPUBLIC "-//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>whereid = #{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关键字,同时去掉最后多余的“,”比如我们只更新提交的不为空的字段,如果提交的数据是空或者"",那么这个字段我们将不更新。*/@Testpublic 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 mapperPUBLIC "-//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_typeFROM `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 {/*** 只有一个分支会被选择!!!!*/@Testpublic 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,"燃油车");// 两个条件为NullList<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 mapperPUBLIC "-//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 mapperPUBLIC "-//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 {@Testpublic 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 mapperPUBLIC "-//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 {@Testpublic 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 mapperPUBLIC "-//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 {@Testpublic 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. 最后:
“在这个最后的篇章中,我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉,我从你们身上吸取了无尽的灵感与勇气。我会将你们的鼓励留在心底,继续在其他的领域奋斗。感谢你们,我们总会在某个时刻再次相遇。”