动态SQL
前言
为什么要使用到 动态SQL这个知识点?
动态SQL 顾名思义 告诉我们 可以灵活的组装 sql 语句。我们可以根据具体的条件 ,调整sql 语句避免了 单一sql 语句的反复堆砌。【避免把sql 语句的条件写死】
动态SQL 被使用在哪?
- mapper 映射文件
常用的动态SQL 中的元素
元素 | 说明 |
<if> | 判断语句,用于单条件判断 |
<choose>(<when>,<otherwise> | 相当于Java 中的switch...case...default语句 用于多条件判断 |
<where> | 简化sql 语句中的where 条件判断 |
<trim> | 可以灵活的去除多余的关键字 |
<set> | 用于 sql 语句的动态更新 |
<foreach> | 循环语句,常用于in 语句 等列举条件 |
以下demo(案例)的项目准备
t_customer 表 的字段和 pojo 包下的 Customer 类的属性需要一一对应
导入依赖
- mybatis 依赖 和 mysql-connector-java 依赖
<dependencies><!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.6</version></dependency><!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.16</version></dependency></dependencies>
mybatis-config 配置文件
配置 连接 数据库的环境,加载 映射文件
整个代码如下
<?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><!-- resourse 的值是 关于 数据库配置文件。含有url,username,password ,数据库驱动 等信息--><properties resource="db.properties"></properties><!-- environment 是一个环境,里面包含一个事务管理器,一个数据源 --><environments default="development"><environment id="development"><transactionManager type="JDBC"></transactionManager><dataSource type="POOLED"><!-- 配置数据源信息,主要有 数据库驱动,数据库连接地址,数据库用户名,数据库密码等 --><property name="driver" value="${driverClass}"></property><property name="url" value="${jdbcUrl}"></property><property name="username" value="${username}"></property><property name="password" value="${password}"></property></dataSource></environment></environments><mappers><!-- 使用mapper 标签 指定mapper映射文件--><mapper resource="mapper/CustomerMapper.xml"/></mappers>
</configuration>
条件查询操作
mapper 接口中的方法
//通过 顾客名字和工作 查询顾客信息List<Customer> findCustomerByNameAndJobs(Customer customer);
<if> 元素
应用场景:<if> 元素 类似于 Java 中的if 语句 ,常用于简单的条件判断
格式:<if test=" 表达式"> .....</if>
如果 表达式判断为true ,就 拼接,执行拼接后的sql 语句
demo(案例)
要求:在实际应用中,可以通过某个条件查询,例如 查找某个 客户的信息,可以通过姓名来查询。同时也可以不填姓名来查找客户。此时通过客户姓名来查询 客户信息,就是非必要条件。遇到这种情况,就可以通过 <if> 元素 实现
- <if> 元素 在mapper 映射文件的使用
<select id="findCustomerByNameAndJobs" parameterType="fs.pojo.Customer" resultType="fs.pojo.Customer">select * from t_customer where 1=1<if test="username != null and username != ''">and username like concat('%',#{username},'%')</if><if test="jobs != null and jobs != ''">and jobs = #{jobs}</if></select>
通过浏览代码,发现当使用 <if> 元素 时 只要 test 属性中的表达式为true,就会执行元素中的条件语句。但是在实际应用中,有时需要从多个选项中选择一个去执行。
<choose>, <when>,<otherwise> 元素
应用场景:当使用该元素时,可以理解为Java的 if(){...}else{....} 和 switch(){ case...default..}
格式
<choose>
<when test=" 表达式">....</when>
<otherwise >.....<otherwise>
</choose>
demo(案例)
- 使用<choose>, <when>,<otherwise> 元素mapper 映射文件
<select id="findCustomerByNameAndJobs" parameterType="fs.pojo.Customer" resultType="fs.pojo.Customer">select * from t_customer where 1=1<choose><when test="username != null and username != ''">and username like concat('%',#{username},'%')</when><when test="jobs != null and jobs != ''">and jobs = #{jobs}</when><otherwise>and phone is not null</otherwise></choose></select>
<where>,<trim> 元素
<where> 元素
在之前 demo案例中 都需要添加where 1=1 这个条件,而加入条件 ”1=1“ 后 ,既保证了where 后面的条件成立,有避免了where 后面第一个词是 and 或者 or 之类的关键字。但如果去掉这个条件,就直接和 and等其他的关键字相连。这就会导致问题。
因此这就是为什么要学习 <where> 元素
<where> 元素 就相当于sql 语句中的where
<trim> 元素
属性 | 说明 |
prefx | 指定给sql 语句增加的前缀 |
prefixOverrides | 指定给sql 语句要去掉的前缀字符串 |
suffix | 指定给sql语句 增加的后缀 |
suffixOverrides | 指定给sql 语句要去掉后缀字符串 |
demo(案例)
<where>元素 在mapper 映射文件的使用
<select id="findCustomerByNameAndJobs" parameterType="fs.pojo.Customer" resultType="fs.pojo.Customer">select * from t_customer <where><if test="username != null and username != ''">and username like concat('%',#{username},'%')</if><if test="jobs != null and jobs != ''">and jobs = #{jobs}</if></where>
注意:当使用<where> 元素,时,跟他紧邻的and 可以自由控制【删除或增加】
- <trim> 元素 在mapper 映射文件的使用
<select id="findCustomerByNameAndJobs" parameterType="fs.pojo.Customer" resultType="fs.pojo.Customer">select * from t_customer <trim prefix="where" prefixOverrides="and"><if test="username != null and username != ''">and username like concat('%',#{username},'%')</if><if test="jobs != null and jobs != ''">and jobs = #{jobs}</if></trim></select>
更新操作
<set>元素
mapper 接口中的方法
//更新用户信息void updateCustomerBySet(Customer customer);
<set> 元素 相当于sql语句中的set 关键字
demo(案例)
- <set> 元素 在mapper 映射文件的使用
<update id="updateCustomerBySet" parameterType="fs.pojo.Customer">update t_customer<set><if test="username != null and username != ''">username = #{username},</if><if test="phone != null and phone != ''">phone = #{phone},</if><if test="jobs != null and jobs != ''">jobs = #{jobs},</if></set>
注意:当使用<set> 元素,时,最后一个 , 可以自由控制【删除或增加】
复杂查询操作
mapper 接口中的方法
//批量查询顾客 信息List<Customer> findByArray(Integer [] ids);List<Customer> findByList( List<Integer> ids);List<Customer> findByMap( Map<String, Object> conditions );
<foreach>元素
为什么要学习<foreach>元素?
这里可以理解我们学习 Java中的 for 循环。我们之前学习 for 循环是为了解决 条件不变情况下的多次输出/打印。这里也是如此。如果客户表里有1000条数据,现在需要将id小于100的客户信息查询出来。这时候如果使用一条条 的sql 查询语句,显然是不现实的,因此借用 for循环的思想 ,循环打印 sql语句。
怎么学习<foreach>元素?
- 了解如何使用 <foreach>元素 中的属性
属性名 | 类型 | 描述 | 是否必填 | 示例 |
---|---|---|---|---|
collection | 字符串 | 指定要遍历的集合或数组的名称。可以是方法参数名、对象属性名、list 、array 、map 等。 | 是 | collection="list" <br>collection="user.ids" <br>collection="map.values" |
item | 字符串 | 为集合中的每个元素指定一个别名,用于在 <foreach> 内部引用。 | 是 | item="item" <br>item="id" <br>item="user" |
index | 字符串 | 为集合中的每个元素指定索引别名,用于在 <foreach> 内部引用索引。 | 否 | index="index" <br>index="i" |
open | 字符串 | 在 <foreach> 生成的 SQL 片段的开头添加的字符串。 | 否 | open="(" <br>open="[" |
separator | 字符串 | 在 <foreach> 生成的 SQL 片段中,每个元素之间插入的分隔符。 | 否 | separator="," <br>separator=" OR " |
close | 字符串 | 在 <foreach> 生成的 SQL 片段的结尾添加的字符串。 | 否 | close=")" <br>close="]" |
重点:学习 <foreach>元素 主要是了解 元素中collection 属性值 array 数组 ,list 集合, 以及 map 键名
collection 属性值 array 数组
<select id="findByArray" parameterType="java.util.Arrays" resultType="fs.pojo.Customer">select * from t_customer where id in<foreach collection="Customer" item="id" open="(" close=")" separator=",">#{id}</foreach></select>
collection 属性值,list 集合
<select id="findByList" parameterType="java.util.List" resultType="fs.pojo.Customer">select * from t_customer where id in<foreach collection="list" item="id" open="(" close=")" separator=",">#{id}</foreach></select>
collection 属性值 map 键名
<select id="findByMap" parameterType="java.util.Map" resultType="fs.pojo.Customer">select * from t_customer where jobs=#{jobs} and id in<foreach collection="ids" item="id" open="(" close=")" separator=",">#{id}</foreach></select>
疑问
为什么 要使用 map ?
在实际情况中,我们向 sql 语句中可能传递多个参数,这时候需要使用到map。 例如 我要查询性别为男 且 id<10 的客户信息
当使用map 时,怎么确定collection 属性值?
我们清楚 map 有一个很重要的知识点:key-value
因此如果我们需要循环遍历某个字段,传递的参数必须要存在一个与之对应的key存入 map中.在下面的代码就是 我需要遍历的是id ,因此 collection 属性值为 ids
List<Integer> ids = new ArrayList<>();ids.add(1);ids.add(2);ids.add(3);Map<String,Object> conditions = new HashMap<>();conditions.put("jobs","teacher");conditions.put("ids",ids);