【Mybatis】动态SQL最全解析

引用

在使用 JDBC 的过程中, 根据条件进行 SQL 的拼接是很麻烦且很容易出错的。 MyBatis 动态 SQL 的出现, 解决了这个麻烦。Mybatis提供了动态SQL,可以根据用户提供的参数,动态决定查询语句依赖的查询条件或SQL语句的内容。
目前, MyBatis 动态 SQL 支持以下几种标签

元素 作用 备注
if 判断语句 单条件分支
choose(when、otherwise) 相当于 Java 中的 if else 多条件分支
trim(where、set) 辅助元素 用于处理 SQL 拼接问题
foreach 循环语句 批量插入, 更新, 查询时经常用到
bind 创建一个变量, 并绑定到上下文中 用于兼容不同的数据库, 防止 SQL 注入等

在介绍各标签使用前,我们先创建一个Spring整合Mybatis工程 【Spring】Spring整合Mybatis案例
工程目录结构如下:
在这里插入图片描述

数据库中创建一张user

DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=49 DEFAULT CHARSET=utf8;

if 标签

if 标签需要配合 test 属性联合使用,通常在查询、删除、更新的时候用到

查询条件

根据输入的用户信息进行条件检索

  • 当只输入name名时, 使用name进行模糊检索;
  • 当只输入age时, 使用age条件进行匹配
  • nameage都存在时, 用这两个条件进行查询匹配查询

接口方法

@Repository("userMapper")
@Mapper
public interface UserMapper {
    
    
    List<User> selectByUserSelective(User user);
}

动态 SQL

UserMapper.xml中添加动态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.lucas.mybatis.mapper.UserMapper">
    <select id="selectByUserSelective" resultType="com.lucas.mybatis.model.User"
            parameterType="com.lucas.mybatis.model.User">
        select * from user where 1=1
        <if test="name != null and name !=''">
            and name like concat('%', #{name}, '%')
        </if>
        <if test="age != null and age > 0">
            and age>#{age}
        </if>
    </select>
</mapper>

测试代码

数据库中添加一些数据
在这里插入图片描述

测试1:

public class App {
    
    
    public static void main(String[] args) {
    
    
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserMapper userMapper = (UserMapper) applicationContext.getBean("userMapper");
        User user = new User();
        user.setName("张");
        List<User> users = userMapper.selectByUserSelective(user);
        for (User user1 : users) {
    
    
            System.out.println(user1);
        }
    }
}

在这里插入图片描述

测试2:

public class App {
    
    
    public static void main(String[] args) {
    
    
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserMapper userMapper = (UserMapper) applicationContext.getBean("userMapper");
        User user = new User();
        user.setAge(18);
        List<User> users = userMapper.selectByUserSelective(user);
        for (User user1 : users) {
    
    
            System.out.println(user1);
        }
    }
}

在这里插入图片描述

测试3:

public class App {
    
    
    public static void main(String[] args) {
    
    
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserMapper userMapper = (UserMapper) applicationContext.getBean("userMapper");
        User user = new User();
        user.setName("张");
        user.setAge(18);
        List<User> users = userMapper.selectByUserSelective(user);
        for (User user1 : users) {
    
    
            System.out.println(user1);
        }
    }
}

在这里插入图片描述

choose(when、otherwise) 标签

choose 标签类似于switch语句,配合whenotherwise 标签,一个 choose标签至少有一个 when, 最多一个otherwise

动态 SQL

UserMapper.xml中添加动态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.lucas.mybatis.mapper.UserMapper">
    <select id="selectByUserSelective" resultType="com.lucas.mybatis.model.User"
            parameterType="com.lucas.mybatis.model.User">
        select * from user where 1=1
        <choose>
            <when test="name != null and name !=''">
                and name like concat('%', #{name}, '%')
            </when>
            <when test="age != null and age > 0">
                and age>#{age}
            </when>
            <otherwise>
                and id =#{id}
            </otherwise>
        </choose>
    </select>
</mapper>

测试代码

还是使用前面的测试数据
在这里插入图片描述

测试1:

public class App {
    
    
    public static void main(String[] args) {
    
    
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserMapper userMapper = (UserMapper) applicationContext.getBean("userMapper");
        User user = new User();
        user.setName("张");
        user.setAge(18);
        user.setId(2);
        List<User> users = userMapper.selectByUserSelective(user);
        for (User user1 : users) {
    
    
            System.out.println(user1);
        }
    }
}

这里的nameage 条件都匹配,但是只拼接了第一个条件
在这里插入图片描述
测试2:

public class App {
    
    
    public static void main(String[] args) {
    
    
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserMapper userMapper = (UserMapper) applicationContext.getBean("userMapper");
        User user = new User();
        user.setId(2);
        List<User> users = userMapper.selectByUserSelective(user);
        for (User user1 : users) {
    
    
            System.out.println(user1);
        }
    }
}

这里的nameage 条件都不匹配,拼接otherwise里面的条件在这里插入图片描述

where标签

前面的if条件中如果我们 把where 后的 1=1 去掉,

  • 当条件都不满足时: 此时 SQL 中应该要不能有 where , 否则导致出错
  • 当 if 有条件满足时: SQL 中需要有 where, 且第一个成立的 if 标签下的 and | or 等要去掉
    <select id="selectByUserSelective" resultType="com.lucas.mybatis.model.User"
            parameterType="com.lucas.mybatis.model.User">
        select * from user where 1=1
        <if test="name != null and name !=''">
            and name like concat('%', #{name}, '%')
        </if>
        <if test="age != null and age > 0">
            and age>#{age}
        </if>
    </select>

我们只需在外层加个where即可解决这种问题

 <select id="selectByUserSelective" resultType="com.lucas.mybatis.model.User"
            parameterType="com.lucas.mybatis.model.User">
        select * from user
        <where>
            <if test="name != null and name !=''">
                and name like concat('%', #{
    
    name}, '%')
            </if>
            <if test="age != null and age > 0">
                and age>#{
    
    age}
            </if>
        </where>
    </select>

set 标签

在 update更新中一般可以使用set标签

动态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.lucas.mybatis.mapper.UserMapper">
    <update id="selectByUserSelective"
            parameterType="com.lucas.mybatis.model.User">
        update user
        <set>
            <if test="name != null and name !=''">name = #{
    
    name},</if>
            <if test="age != null and age > 0">age= #{
    
    age}</if>
        </set>
        <where>id = #{
    
    id}</where>
    </update>
</mapper>

测试代码

public class App {
    
    
    public static void main(String[] args) {
    
    
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserMapper userMapper = (UserMapper) applicationContext.getBean("userMapper");
        User user = new User();
        user.setName("张三3");
        user.setAge(19);
        user.setId(2);
        int result = userMapper.selectByUserSelective(user);
        System.out.println(result);
   
    }
}

在这里插入图片描述

trim标签

trim标签主要功能是在包含的内容前面加上某些前缀和后缀。
前面的setwhere 其实都是 trim 标签的一种类型, 该两种功能都可以使用 trim 标签进行实现。

trim 标签常用元素如下:

  • prefix: 当 trim 元素包含有内容时, 增加 prefix 所指定的前缀
  • prefixOverrides: 当 trim 元素包含有内容时, 去除 prefixOverrides 指定的 前缀
  • suffix: 当 trim 元素包含有内容时, 增加 suffix 所指定的后缀
  • suffixOverrides: 当 trim 元素包含有内容时, 去除 suffixOverrides 指定的后缀

前面的where可以用 trim 表示如下:

<trim prefix="where" prefixOverrides="AND |OR"></trim>

前面的where动态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.lucas.mybatis.mapper.UserMapper">
    <select id="selectByUserSelective" resultType="com.lucas.mybatis.model.User"
            parameterType="com.lucas.mybatis.model.User">
        select * from user
        <trim prefix="where" prefixOverrides="AND |OR">
            <if test="name != null and name !=''">
                and name like concat('%', #{
    
    name}, '%')
            </if>
            <if test="age != null and age > 0">
                and age>#{
    
    age}
            </if>
        </trim>
    </select>
</mapper>

set 标签可以 trim 表示如下:

<trim prefix="SET" suffixOverrides=","></trim>

前面的set 动态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.lucas.mybatis.mapper.UserMapper">
    <update id="selectByUserSelective"
            parameterType="com.lucas.mybatis.model.User">
        update user
        <trim prefix="SET" suffixOverrides=",">
            <if test="name != null and name !=''">name = #{
    
    name},</if>
            <if test="age != null and age > 0">age= #{
    
    age}</if>
        </trim>
        <where>id = #{
    
    id}</where>
    </update>
</mapper>

foreach 标签

foreach 标签常用语in条件中
foreach 标签可以对数组, Map 或实现 Iterable 接口。

foreach 中常用属性如下:

  • collection: 必填, 集合/数组/Map的名称.
  • item: 变量名。 即从迭代的对象中取出的每一个值
  • index: 索引的属性名。 当迭代的对象为 Map 时, 该值为 Map 中的 Key.
  • open: 循环开头的字符串
  • close: 循环结束的字符串
  • separator: 每次循环的分隔符

接口方法

@Repository("userMapper")
@Mapper
public interface UserMapper {
    
    
   List<User> selectByUserSelective(List<Integer> list);
}

动态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.lucas.mybatis.mapper.UserMapper">
    <select id="selectByUserSelective" resultType="com.lucas.mybatis.model.User"
            parameterType="java.util.List">
        select * from user where id in
        <foreach collection="list" item="id" open="(" close=")" separator="," index="i">      #{
    
    id}
        </foreach>
    </select>
</mapper>

测试代码

public class App {
    
    
    public static void main(String[] args) {
    
    
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserMapper userMapper = (UserMapper) applicationContext.getBean("userMapper");
         List<Integer> list = new ArrayList<>();
        list.add(2);
        list.add(48);
        list.add(49);
        List<User> users = userMapper.selectByUserSelective(list);
       for (User user1 : users) {
    
    
           System.out.println(user1);
        }
    }
}

执行结果如下:
在这里插入图片描述

collection 值的指定

  • 当接口方法中只有一个参数,集合collection的值填list, 数组collection的值填array
  • 当接口方法中只有一个参数,也可以使用 @Param 来指定参数的名称
public interface UserMapper {
    
    
   List<User> selectByUserSelective
   			(@Param("mylist") List<Integer> list1);
}

 <foreach collection="mylist" item="id" 
 open="(" close=")" separator="," index="i">      #{
    
    id}
  </foreach>
  • 当接口中有多参数用 @Param 来指定

bind 标签

bind标签用于拼接字段形成新的变量,常用于like查询等


<select id="selectByUserSelective"  
		resultType="com.lucas.mybatis.model.User"
        parameterType="com.lucas.mybatis.model.User">
    select * from user
    <bind name="nameLike" value="'%' + name + '%'"/>
    <where>
        <if test="name != null and name !=''">
            and name like  #{
    
    nameLike}
        </if>
        <if test="age != null and age > 0">
            and age>#{
    
    age}
        </if>
    </where>
</select>

猜你喜欢

转载自blog.csdn.net/huweiliyi/article/details/107935405