19---动态SQL+MyBatis多表关联

本文详细介绍了MyBatis中的动态SQL,包括if、where、set和foreach标签的使用,以及动态SQL环境搭建。同时,讲解了一对一、一对多和多对多的多表关联查询,包括延迟加载和缓存机制。通过实例展示了如何在映射文件中配置和测试这些功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


typora-root-url: img
typora-copy-images-to: img

MyBatis(第3天) 动态SQL和多表关联

回顾

  1. 说说核心配置文件中这些标签的作用
配置标签名称 功能 属性或子元素
properties 加载外部Java属性配置 属性 resource:.properties文件的路径

子元素property:如果和外部引入的重名了,使用外部的
typeAliases 定义POJO类的别名 子元素 typeAliase: 给每个类取别名
子元素 package: 给这个包里面的所有类取别名,别名就是类名
mappers 加载外部的映射文件 子元素 mapper: 指定一个映射文件的位置
子元素 package: 加载这个包里面的所有映射文件

1.接口和映射文件要在同一个包

2.接口和映射文件的名称要相同
  1. 说说下面映射文件中标签的作用
标签 子标签 说明
<select> 表示查询的SQL
<insert> 表示插入的SQL
<selectKey> 得到自增的主键
<update> 表示修改的SQL
<delete> 表示删除的SQL
  1. resultMap标签的作用
标签名 属性
resultMap id: 结果映射的唯一标识
type: 结果映射的类型
子标签id和result column: 查询出来的字段名
property:类中的成员变量名
  1. 说说下面注解的作用
注解 描述
@Select 表示查询的SQL
@Results 对结果进行映射
@Result 对一个字段进行映射
@Update 表示修改的SQL
@Delete 表示删除的SQL
@Insert 表示插入的SQL
@SelectKey 得到自增的主键

学习目标

  1. 掌握 MyBatis 多表关联查询
  2. MyBatis 的延迟加载
  3. 注解实现多表关联查询
  4. 掌握二级缓存的开启配置

今日模块名

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);
        }
    }
}

小结

  1. 搭建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

  1. if:判断用户名称不为空,且不为空字符串,则用户名称作为查询条件
  2. 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 &amp;&amp; sex!=''">
          and sex = #{sex}
        </if>
    </select>
</mapper>

测试

  1. 通过用户名和性别查询多个用户
  2. 只设置性别
  3. 名字和性别一个都不设置
@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标签作用
  1. 相当于where关键字,自动补全where这个关键字
  2. 去掉多余的and和or关键字
需求实现
UserMapper.xml

if标签写在where标签内部

  1. if:判断用户名称不为空,且不为空字符串,则用户名称作为查询条件
  2. 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 &amp;&amp; sex != ''">
            AND sex=#{sex};
        </if>
    </where>
</select>

小结

  1. if标签的作用:

    做判断,如果满足条件就拼接SQL

  2. where标签的作用

    1. 替代WHERE关键字
    2. 如果有条件会自动添加WHERE关键字
    3. 如果没有条件就不添加WHERE关键字
    4. 去掉多余的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标签的作用
  1. 用在update语句中,相当于set关键字
  2. 去掉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, 68});

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值