typora-root-url: img
typora-copy-images-to: img
MyBatis(第3天) 动态SQL和多表关联
回顾
- 说说核心配置文件中这些标签的作用
配置标签名称 | 功能 | 属性或子元素 |
---|---|---|
properties | 加载外部Java属性配置 | 属性 resource:.properties文件的路径 子元素property:如果和外部引入的重名了,使用外部的 |
typeAliases | 定义POJO类的别名 | 子元素 typeAliase: 给每个类取别名 子元素 package: 给这个包里面的所有类取别名,别名就是类名 |
mappers | 加载外部的映射文件 | 子元素 mapper: 指定一个映射文件的位置 子元素 package: 加载这个包里面的所有映射文件 1.接口和映射文件要在同一个包 2.接口和映射文件的名称要相同 |
- 说说下面映射文件中标签的作用
标签 | 子标签 | 说明 |
---|---|---|
<select> | 表示查询的SQL | |
<insert> | 表示插入的SQL | |
<selectKey> | 得到自增的主键 | |
<update> | 表示修改的SQL | |
<delete> | 表示删除的SQL |
- resultMap标签的作用
标签名 | 属性 |
---|---|
resultMap | id: 结果映射的唯一标识 type: 结果映射的类型 |
子标签id和result | column: 查询出来的字段名 property:类中的成员变量名 |
- 说说下面注解的作用
注解 | 描述 |
---|---|
@Select | 表示查询的SQL |
@Results | 对结果进行映射 |
@Result | 对一个字段进行映射 |
@Update | 表示修改的SQL |
@Delete | 表示删除的SQL |
@Insert | 表示插入的SQL |
@SelectKey | 得到自增的主键 |
学习目标
- 掌握 MyBatis 多表关联查询
- MyBatis 的延迟加载
- 注解实现多表关联查询
- 掌握二级缓存的开启配置
今日模块名
mybatis_day03_01_multi_table: 多表关联查询
mybatis_day03_02_lazy: 延迟加载
mybatis_day03_03_ann_multi_table: 注解配置多表关联查询
动态SQL的概念和环境搭建
之前我们编写SQL语句的时候都是将SQL语句固定写好的
SELECT * FROM product WHERE brand='小米' AND type='ai' AND size=55;
UPDATE user SET username=#{username}, birthday=#{birthday}, sex=#{sex}, address=#{address} WHERE id=#{id};
目标
学习动态SQL的概念
搭建动态SQL的环境
什么是动态SQL
(动态SQL在代码实现上实际上就是拼接SQL语句)
[外链图片转存失败(img-Oa07mz9a-1565448563923)(/…/…/…/…/…/…/1a%E9%BB%91%E9%A9%ACjava/%E9%BB%91%E9%A9%ACjava/%E5%B0%B1%E4%B8%9A%E7%8F%AD/day18—MyBatis%E4%B8%89%E7%A7%8D%E5%BC%80%E5%8F%91%E6%96%B9%E5%BC%8F+%E5%8F%8A%E5%85%B6%E5%A2%9E%E5%88%A0%E6%94%B9%E6%9F%A5/source/1562723542603.png)]
动态SQL指的是:在程序运行时,根据传入的参数情况,拼接最终执行的sql语句。
[外链图片转存失败(img-auTZ1kQy-1565448563924)(/1562723542603.png)]
搭建动态SQL的环境
模块名:mybatis_day02_04_dynamic_sql
配置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>
<properties resource="jdbc.properties"/>
<typeAliases>
<package name="com.itheima.entity"/>
</typeAliases>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="dirver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<package name="com.itheima.dao"/>
</mappers>
</configuration>
测试
public class TestApp {
// 省略其他sqlSession的创建
@Test
public void testFindUserBySex() {
List<User> list = userMapper.findUserByNameAndSex(new QueryVo("%王%", "女"));
for (User user : list) {
System.out.println("user = " + user);
}
}
}
小结
- 搭建mybatis环境
动态SQL:if标签
目标
用户名和性别查询用户
学习动态SQL语句:if标签的使用
if标签的格式
<if test="条件">
SQL语句
</if>
if标签的作用
如果满足条件,就会拼接这个SQL。
需求实现
定义QueryVo实体类
public class QueryVo {
private String username;
private String sex;
// 省略构造方法/getter/setter
}
声明UserMapper接口方法
package com.itheima.dao;
import com.itheima.entity.User;
import java.util.List;
public interface UserMapper {
/*
根据用户名称和性别查询用户
*/
List<User> findUserByNameAndSex(QueryVo vo);
}
配置mappr映射文件
<?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" >
<mapper namespace="com.itheima.dao.UserMapper">
<select id="findUserByNameAndSex" parameterType="queryvo" resultType="User">
SELECT * FROM user WHERE username LIKE #{username} AND sex=#{sex};
</select>
</mapper>
UserMapper.xml
- if:判断用户名称不为空,且不为空字符串,则用户名称作为查询条件
- if:判断用户性别不为空,且不为空字符串,则用户性别作为查询条件
<?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" >
<mapper namespace="com.itheima.dao.UserMapper">
<!--直接根据用户名和性别查询-->
<!-- <select id="findUserByNameAndSex" parameterType="queryvo" resultType="User">
SELECT * FROM user WHERE username LIKE #{username} AND sex=#{sex};
</select>-->
<!--
判断用户名称不为空,且不为空字符串,则用户名称作为查询条件
判断用户性别不为空,且不为空字符串,则用户性别作为查询条件
-->
<select id="findUserByNameAndSex" parameterType="User" resultType="User">
select * from user where
<if test="username!=null and username!=''">
username like '%${username}%'
</if>
<!-- &&表示与操作,要转义 -->
<if test="sex!=null && sex!=''">
and sex = #{sex}
</if>
</select>
</mapper>
测试
- 通过用户名和性别查询多个用户
- 只设置性别
- 名字和性别一个都不设置
@Test
public void testFindUserBySex() {
List<User> list = userMapper.findUserByNameAndSex(new QueryVo("", ""));
for (User user : list) {
System.out.println("user = " + user);
}
}
疑问:if标签如果第1个条件没有,会出现什么情况?如何解决这个问题?
因为SQL语句拼接语句不正确,出现问题。
[外链图片转存失败(img-raVFr7dx-1565448563925)(/1564450528189.png)]
小结
动态SQL中if标签
if标签的含义做判断如果条件为true就拼接SQL
if标签的格式:
<if test"条件">
SQL
</if>
动态SQL:where标签的作用
目标
学习where标签的使用
where标签作用
- 相当于where关键字,自动补全where这个关键字
- 去掉多余的and和or关键字
需求实现
UserMapper.xml
if标签写在where标签内部
- if:判断用户名称不为空,且不为空字符串,则用户名称作为查询条件
- if:判断用户性别不为空,且不为空字符串,则用户性别作为查询条件
<select id="findUserByNameAndSex" parameterType="queryvo" resultType="User">
SELECT * FROM user
<where>
<if test="username != null and username != ''">
AND username LIKE #{username}
</if>
<!--&&表示与操作,要转义-->
<if test="sex != null && sex != ''">
AND sex=#{sex};
</if>
</where>
</select>
小结
-
if标签的作用:
做判断,如果满足条件就拼接SQL
-
where标签的作用
- 替代WHERE关键字
- 如果有条件会自动添加WHERE关键字
- 如果没有条件就不添加WHERE关键字
- 去掉多余的AND OR
动态SQL:set标签
目标
使用set标签对修改字段拼接
编写修改SQL语句存在的问题
之前我们编写修改的SQL语句时是根据用户ID更新用户所有字段的数据==(这样存在问题,没有值的字段也会被更新为null,最好是有数据的字段更新,没有数据的字段不更新)==
<!--根据用户ID更新用户所有字段的数据, 这样存在问题,没有值的字段也会被更新为null,最好是有数据的字段更新,没有数据的字段不更新-->
<update id="updateUser" parameterType="user">
UPDATE user SET username=#{username}, birthday=#{birthday}, sex=#{sex}, address=#{address}
WHERE id=#{id};
</update>
更新数据的时候,有些为空则不用更新,怎么来处理呢?
set标签的作用
- 用在update语句中,相当于set关键字
- 去掉SQL代码片段中后面多余的逗号
需求
根据id修改用户部分数据
实现
声明mapper接口方法
/**
更新用户
*/
int updateUser(User user);
配置mapper映射文件:根据id修改用户部分数据
<!--这样存在问题,没有值的字段也会被更新为null,最好是有数据的字段更新,没有数据的字段不更新-->
<update id="updateUser" parameterType="user">
UPDATE user SET username=#{username}, birthday=#{birthday}, sex=#{sex}, address=#{address} WHERE id=#{id};
</update>
测试
@Test
public void testUpdateUser() throws IOException {
User u = new User();
u.setId(26);
u.setUsername("大王");
userMapper.updateUser(u);
}
这样存在问题,没有值的字段也会被更新为null,最好是有数据的字段更新,没有数据的字段不更新。
[外链图片转存失败(img-ZSl3hTqY-1565448563926)(/1562728386445.png)]
[外链图片转存失败(img-gT8C8HyT-1565448563927)(/1562729023088.png)]
使用set标签进行判断,如果有值就更新,没有值就不更新。
<update id="updateUser" parameterType="user">
UPDATE user
<set>
<if test="username != null and username != ''">
username=#{username},
</if>
-- 下面语句不写等于空字符串的条件,是因为Date类型不能和String类型作比较
<if test="birthday != null">
birthday=#{birthday},
</if>
<if test="sex != null and sex != ''">
sex=#{sex},
</if>
<if test="address != null and address != ''">
address=#{address}
</if>
</set>
WHERE id=#{id};
</update>
set标签,可以按照条件拼接set后面的内容
[外链图片转存失败(img-yU4iiIln-1565448563927)(/1562728792369.png)]
小结
set标签的作用是?
相当于Set关键字,会自动去掉多余的,
foreach标签:遍历集合1(映射方法传入参数是数组)
MyBatis得到数组中的数据动态拼接SQL
int row = userMapper.deleteUsers(new int[]{
1, 3, 6, 8});
delete from user where id in (1, 3, 6, 8);
使用数组来封装要删除的所有的id
目标
foreach标签:遍历集合得到基本类型的数据
需求
遍历集合拼接SQL语句,实现批量删除用户
foreach标签介绍
foreach标签的属性 | 作用 |
---|---|
collection | 要遍历的集合,2个取值:list或array |
item | 设置变量名,代表每个遍历的元素 |
separator | 每次遍历完后添加一个分隔符 |
#{变量名.属性} | 来引用每个属性中值 |
实现
声明mapper接口方法
/**
批量删除用户
*/
int deleteUsers(int[] ids);
配置mapper映射文件
<delete id="deleteUsers" parameterType="list">
<!--DELETE FROM user WHERE id in (1, 2, 3);-->
DELETE FROM user WHERE id in
<!--
collection: 取值为array表示遍历的是数组
open: 遍历前添加的符号
close: 遍历最后添加的符号
separator:分隔符
item: 表示每个元素的变量名
-->
<foreach collection="array" open="(" close=");" separator="," item="temp">
#{temp}
</foreach>
</delete>
测试
@Test
public void testDeleteUser() throws IOException {
int row = userMapper.deleteUsers(new int[]{
24, 25, 26});
System.out