2023.11.30 关于 MyBatis 动态 SQL 的使用

目录

引言

if 标签 

trim 标签 

where 标签 

set 标签 

foreach 标签 


引言

  • 动态 sql 是 MyBatis 的强大特性之一
  • 允许你根据输入的参数动态地构建 sql 语句
  • 从而在运行时根据不同的条件生成不同的 sql

核心思想

  • 基于提供的数据和条件,能够修改、增加、删除 sql 语句的部分内容
  • 这为编写更通用、可重用的 sql 提供了极大的灵活性

  • 以下我们介绍 5 个常用的动态 sql 标签

if 标签 

实例理解

  • 此处我们想要实现 根据 name 和 age 字段来筛选用户信息 功能

创建数据库

  • 在数据库中创建一个如下图所示的 user 表,并插入几条用户数据
  • 注意这里的 state 状态
  • 值为 1 表示该用户可正常登录
  • 值为 0 表示该用户异常,无法登录


实现 UserMapper 接口

  • 此处我们实现一个 selectUser 方法
import com.example.demo.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

//添加 @Mapper 注解 代表该接口会伴随这 项目的启动而注入到容器中
@Mapper
public interface UserMapper {

//    根据 name 和 age 字段来筛选用户信息
    List<User> selectUser(@Param("user_name") String name,
                          @Param("user_age") Integer age);
}

实现 UserMapper XML 文件

  • 在与接口相对应的 XML 文件中
  • 添加上与 selectUser 方法 相对应的 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">
<mapper namespace="com.example.demo.mapper.UserMapper">

    <select id="selectUser" resultType="com.example.demo.entity.User">
        select * from user
        where 1=1
        <if test="user_name != null">
             and name = #{user_name}
        </if>
        <if test="user_age != null">
            and age = #{user_age}
        </if>
    </select>

</mapper>

分析功能 与 select 语句

  • 根据 name 和 age 字段筛选用户信息    存在四种情况

情况一:

  • name 和 age 均不为空,其所对应的 sql 语句为:
select * from user where name = #{user_name} and age = #{user_age}

情况二:

  • name 和 age 均为空,其所对应的 sql 语句为:
select * from user

情况三:

  • name 为空, age 不为空,其所对应的 sql 语句为:
select * from user where age = #{user_age}

情况四:

  • name 不为空, age 为空,其所对应的 sql 语句为:
select * from user where name = #{user_name}

分析 XML 中的 select 语句 

  • 加上 if 标签后,该 sql 也将存在四种情况,与上述分析的四种情况相对应

注意:

  • 理解此处加上的 绿框部分,即 '1=1'
  • 如果删除绿框部分,那么我们再观察下图

  • 所以 XML 中的 select 语句必须加上绿框部分,否则将会导致 sql 语法错误

创建 selectUser 的测试方法

  • 我们随意选择上述四种情况的任意一种进行传参
  • 此处我们选择仅传参 age= 20
@Test
    void selectUser() {
        List<User> users = userMapper.selectUser(null,20);
        users.stream().forEach(System.out::println);
    }

执行测试方法

  • 测试方法成功执行

trim 标签 

属性

  • prefix:表示整个语句块,以 prefix 的值作为前缀
  • suffix:表示整个语句块,以 suffix 的值作为后缀
  • prefixOverrides:表示整个语句块,所需要去除的多余前缀
  • suffixOverrides:表示整个语句块,所需要去除的多余后缀

实例理解

  • 下方的 select 查询语句为了保证 sql 语法的正确性,还必须得添加上 '1=1' 
<select id="selectUser" resultType="com.example.demo.entity.User">
        select * from user
        where 1=1
        <if test="user_name != null">
             and name = #{user_name}
        </if>
        <if test="user_age != null">
            and age = #{user_age}
        </if>
    </select>
  • 但是我们可以使用 <trim> 标签来改写上方的 select 语句,使其可以不用添加上 '1=1'的同时保障 sql 语法的正确性
select * from user
        <trim prefix="where" suffixOverrides="and">
            <if test="user_name != null">
                 name = #{user_name} and
            </if>
            <if test="user_age != null">
                 age =#{user_age}
            </if>
        </trim>

分析该 sql 语句

  • 此处经存在一种情况会 发生去除多余后缀 'and' 


注意:

  • 当 <trim> 标签中生成了代码那么才会添加 <trim> 标签里的前缀和后缀
  • 如果 <trim> 标签中未生成代码,则前缀和后缀都会省略

where 标签 

实例理解

  • 我们同样可以使用 <wehre> 标签来改写上述 根据 name 和 age 字段来筛选用户信息 的 sql 语句
<select id="selectUser" resultType="com.example.demo.entity.User">
        select * from user
        <where>
            <if test="user_name != null">
                name = #{user_name}
            </if>
            <if test="user_age != null">
                and age =#{user_age}
            </if>
        </where>
</select>

注意:

  • 上述实例为 <where> 标签的正确写法不能写成下述 sql 语句
<select id="selectUser" resultType="com.example.demo.entity.User">
        select * from user
        <where>
            <if test="user_name != null">
                name = #{user_name} and
            </if>
            <if test="user_age != null">
                age =#{user_age}
            </if>
        </where>
</select>
  • 因为 <where> 标签会帮去除最前面的多余 'and' 关键字 ,而不会帮去除最后面的多余 'and' 关键字
  • 即 <where> 标签相当于 <trim prefix="where" prefixOverrides = "and">

set 标签 

实例理解

  • 此处我们想实现一个 根据用户 id 修改用户各属性 功能

准备数据库

  • 在数据库中准备好一个 user 表


 实现 UserMapper 接口

  • 此处我们实现一个 updateById 方法
import com.example.demo.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

//添加 @Mapper 注解 代表该接口会伴随这 项目的启动而注入到容器中
@Mapper
public interface UserMapper {
//    根据 id 修改用户信息
    Integer updateById(User user);

}

实现 UserMapper XML 文件

  • 在与接口相对应的 XML 文件中
  • 添加上与 updateById 方法 相对应的 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">
<mapper namespace="com.example.demo.mapper.UserMapper">

    <update id="updateById" parameterType="com.example.demo.entity.User">
        update user
        <set>
            <if test="name != null">
                name = #{name},
            </if>
            <if test="age != 0">
                age = #{age},
            </if>
            <if test="password != null">
                password = #{password},
            </if>
            <if test="state != 0">
                state = #{state}
            </if>
        </set>
        where id = #{id}
    </update>

</mapper>

创建 updateById 的测试方法

  • 此处我们修改 用户 id = 4 用户信息
  • 修改其姓名、年龄、密码,不修改其状态
@Test
void updateById() {
    User user = new User();
    user.setId(4);
    user.setName("haoran");
    user.setAge(20);
    user.setPassword("123123");
    int result = userMapper.updateById(user);
    System.out.println("updateById 方法 :" + (result == 1 ? "修改成功" : "修改失败"));
}

执行测试方法

  • 测试方法成功执行

  • 观察数据库中的 user 表


注意:

  • <set> 标签相当于 <trim prefix="set" suffixOverrides = ",">

foreach 标签 

属性

  • collection:绑定方法参数中的集合,如 List、Set、Map 或数组对象
  • item:遍历时的每一个对象
  • open:语块开头的字符串
  • close:语块结束的字符串
  • separator:每次遍历之间间隔的字符串

实例理解

  • 此处想实现一个 根据多个用户 Id 来批量封禁用户 功能

 准备数据库

  • 在数据库中准备好一个 user 表


 实现 UserMapper 接口

  • 此处我们实现一个 updateStateByIds 方法
import com.example.demo.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

//添加 @Mapper 注解 代表该接口会伴随这 项目的启动而注入到容器中
@Mapper
public interface UserMapper {
//    根据多个 id 批量封禁用户
    Integer updateStateByIds(@Param("user_ids") List<Integer> ids);
}

实现 UserMapper XML 文件

  • 在与接口相对应的 XML 文件中
  • 添加上与 updateStateByIds 方法 相对应的 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">
<mapper namespace="com.example.demo.mapper.UserMapper">

    <update id="updateStateByIds">
        update user set state = 0
        where id in
        <foreach collection="user_ids" item="item" open="(" close=")" separator=",">
            #{item}
        </foreach>
    </update>

</mapper>

创建 updateStateByIds 的测试方法

  • 此处我们封禁 id = 1、4、8、9  的用户
@Test
void updateStateByIds() {
    List<Integer> ids = new ArrayList<>();
    ids.add(1);
    ids.add(4);
    ids.add(8);
    ids.add(9);
    int result = userMapper.updateStateByIds(ids);
    System.out.println("updateById 方法 :" + (result > 1 ? "修改成功" : "修改失败"));
}

执行测试方法

  • 测试方法成功执行

  • 观察数据库中的 user 表

  • 20
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

茂大师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值