四、MyBatis动态语句

四、MyBatis动态语句

1、动态语句需求和简介

1、需求

1、应对多个条件查询。

2、有很多条件不满足的。

2、简介

1、动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。

2、使用动态 SQL 并非一件易事,但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显著地提升了这一特性的易用性。

3、如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。

2、if和where标签

1、if标签

1、就是用来进行判断,哪些条件需要加

2、内容

  • if 判断传入的参数,最终是否添加语句
  • test属性: 内部做比较运算,最终true将标签内的sql语句进行拼接。如果为false就不拼接
  • 判断语句:“key 比较符号 值 and | or key 比较符号 值 ”
  • 大于小于不推荐直接使用符号。一般用实体符号来表示 大于:> 小于: <

2、where条件

1、就是用来解决,if判断中可能出现的问题

2、问题

  • 如果两个条件都满足
  • 如果第一个条件满足 emp_name = #{name}
  • 如果第一个条件不满足,第二个条件满足
  • 如果两个都不满足

3、where的作用

  • 自动添加where关键字 where内部有任何一个if满足,就自动添加where关键字,否则去掉
  • 自动去掉多余的and 和or

3、例子

1、准备实体类

package com.atgui.pojo;

public class Employee {
    private int empId;
    private String empName;
    private String empSalary;

    public int getEmpId() {
        return empId;
    }

    public void setEmpId(int empId) {
        this.empId = empId;
    }

    public String getEmpName() {
        return empName;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    public String getEmpSalary() {
        return empSalary;
    }

    public void setEmpSalary(String empSalary) {
        this.empSalary = empSalary;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "empId=" + empId +
                ", empName='" + empName + '\'' +
                ", empSalary='" + empSalary + '\'' +
                '}';
    }
}

2、准备接口

package com.atgui.mapper;

import com.atgui.pojo.Employee;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface EmployeeMapper {

    List<Employee> query(@Param("name") String  name,@Param("salary") Double salary);
}

3、准备employee.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace等于mapper接口类的全限定名,这样实现对应 -->
<mapper namespace="com.atgui.mapper.EmployeeMapper">

<!--
            场景:如果传入属性,就判断相等,如果不传入,就不加对应的条件
                where
                if 判断传入的参数,最终是否添加语句
                    test属性: 内部做比较运算,最终true将标签内的sql语句进行拼接。如果为false就不拼接

                    判断语句:“key 比较符号 值 and | or key 比较符号 值 ”
                    大于小于不推荐直接使用符号。一般用实体符号来表示 大于:>   小于: <

                还有遇到的问题
                    如果两个条件都满足
                    如果第一个条件满足 emp_name = #{name}
                    如果第一个条件不满足,第二个条件满足
                    如果两个都不满足

                   解决:这里我们要用 where标签
                        where好处:
                            1、自动添加where关键字 where内部有任何一个if满足,就自动添加where关键字,否则去掉
                            2、自动去掉多余的and 和or
-->

    <select id="query" resultType="employee">
        select * from t_emp
        <where>
            <if test="name!=null">
                emp_name = #{name}
            </if>
            <if test="salary !=null and  salary >100 ">
                and emp_salary =#{salary}
            </if>
        </where>
    </select>

</mapper>

4、准备mybatis-config.xml

<?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>
<!--    让mybatis开启日志输出-->
    <settings>
<!--        这里设置的是选择用system进行日志输出-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>

<!--        开启驼峰式自动映射-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>

        <!--开启resultMap自动映射 -->
        <setting name="autoMappingBehavior" value="FULL"/>
    </settings>

<!--    定义自己类的别名-->
    <typeAliases>
<!--        单独定义-->
<!--        <typeAlias type="com.atgui.pojo.Employee" alias="suibian"/>-->
<!--        批量定义-->
        <package name="com.atgui.pojo"/>
    </typeAliases>

    <!-- environments表示配置Mybatis的开发环境,可以配置多个环境,在众多具体环境中,使用default属性指定实际运行时使用的环境。default属性的取值是environment标签的id属性的值。 -->
    <environments default="development">
        <!-- environment表示配置Mybatis的一个具体的环境 -->
        <environment id="development">
            <!-- Mybatis的内置的事务管理器 -->
            <transactionManager type="JDBC"/>
            <!-- 配置数据源 -->
            <dataSource type="POOLED">
                <!-- 建立数据库连接的具体信息 -->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis-example"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <!-- Mapper注册:指定Mybatis映射文件的具体位置 -->
        <!-- mapper标签:配置一个具体的Mapper映射文件 -->
        <!-- resource属性:指定Mapper映射文件的实际存储位置,这里需要使用一个以类路径根目录为基准的相对路径 -->
        <!--    对Maven工程的目录结构来说,resources目录下的内容会直接放入类路径,所以这里我们可以以resources目录为基准 -->
        <mapper resource="mappers/EmployeeMapper.xml"/>

    </mappers>

</configuration>

5、测试

package com.atgui;

import com.atgui.mapper.EmployeeMapper;
import com.atgui.pojo.Employee;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class mybatisTest {
    private SqlSession sqlSession;

    //    每次测试方法执行前都会执行该代码
    @BeforeEach
    public void before() throws IOException {
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        sqlSession = sqlSessionFactory.openSession(true);
    }

    //每次测试方法执行后都会执行该代码
    @AfterEach
    public void clean(){
        sqlSession.close();
    }

    @Test
    public void  test1(){
        EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
        List<Employee> list =  employeeMapper.query(null,100.0);
        System.out.println("list = " + list);
    }
}

3、set标签

1、作用

1、 使用set标签动态管理set子句,并且动态去掉两端多余的逗号

2、会自动添加set关键字

2、例子

1、代码

 <update id="update">
        update t_emp
<!--        set作用:
                1、自动去掉多余的,
                2、自动添加set关键字
-->
        <set>
            <if test="empName!=null">
                emp_name = #{empName},
            </if>
            <if test="empSalary !=null">
                emp_salary = #{empSalary},
            </if>
        </set>
    </update>

4、trim标签(了解)

1、作用

1、目前的作用是来替代where语句

2、可以控制条件部分两端是否包含某些字符串

2、属性

  • prefix属性:指定要动态添加的前缀
  • suffix属性:指定要动态添加的后缀
  • prefixOverrides属性:指定要动态去掉的前缀,使用“|”分隔有可能的多个值
  • suffixOverrides属性:指定要动态去掉的后缀,使用“|”分隔有可能的多个值

3、例子

<!-- List<Employee> selectEmployeeByConditionByTrim(Employee employee) -->
<select id="selectEmployeeByConditionByTrim" resultType="com.atguigu.mybatis.entity.Employee">
    select emp_id,emp_name,emp_age,emp_salary,emp_gender
    from t_emp

    <!-- prefix属性指定要动态添加的前缀 -->
    <!-- suffix属性指定要动态添加的后缀 -->
    <!-- prefixOverrides属性指定要动态去掉的前缀,使用“|”分隔有可能的多个值 -->
    <!-- suffixOverrides属性指定要动态去掉的后缀,使用“|”分隔有可能的多个值 -->
    <!-- 当前例子用where标签实现更简洁,但是trim标签更灵活,可以用在任何有需要的地方 -->
    <trim prefix="where" suffixOverrides="and|or">
        <if test="empName != null">
            emp_name=#{empName} and
        </if>
        <if test="empSalary > 3000">
            emp_salary>#{empSalary} and
        </if>
        <if test="empAge <= 20">
            emp_age=#{empAge} or
        </if>
        <if test="empGender=='male'">
            emp_gender=#{empGender}
        </if>
    </trim>
</select>

5、choose/when/otherwise标签

1、作用

1、在多分支条件上,仅执行一个

  • 从上到下依次执行条件判断
  • 遇到的第一个满足条件的分支会被采纳
  • 被采纳分支后面的分支都将不被考虑
  • 如果所有的when分支都不满足,那么就执行otherwise分支

2、例子

<select id="selectEmployeeByConditionByChoose" resultType="employee">
        select emp_id ,emp_name,emp_salary
        from t_emp
        where
        <choose>
            <when test="enpName != null">
                emp_name =#{empName}
            </when>
        </choose>
    </select>

6、foreach标签

1、基本用法

1、属性

  • 1、collection:要遍历的集合
  • 2、open:遍历之前追加的字符串
  • 3、close:遍历结束需要添加的字符串
  • 4、separator:每次遍历的分割符号,如果是最后一次,不会追加
  • 5、item:获取每个遍历项

2、就是找规律,看sql语句哪些能够用foreach套用然后遍历

2、注意

1、如果都没有规律,就把整个sql语句包裹起来,整体循环

2、有个前提:需要开启批量sql语句执行的语句

3、修改jdbc配置

 <!-- 配置数据源 -->
            <dataSource type="POOLED">
                <!-- 建立数据库连接的具体信息 -->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis-example?allowMultiQueries=true"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>

4、还有就是collection属性。建议用@Param注解指定一个具体名字。否则难理解

5、在实际开发中,为了避免隐晦的表达造成一定的误会,建议使用@Param注解明确声明变量的名称,然后在foreach标签的collection属性中按照@Param注解指定的名称来引用传入的参数。

3、例子

1、mapper接口文件

//    根据id的批量查询
    List<Employee> queryBatch(@Param("ids") List<Integer> ids);
//    根据id的批量删除
    int deleteBatch(@Param("ids") List<Integer> ids);
//    批量添加
    int insertBatch(@Param("list") List<Employee> employeeList);
//    批量修改
    int updateBatch(@Param("list") List<Employee> employeeList);

2、sql语句

<!--    List<Employee> queryBatch(@Param("ids") List<Integer> ids);-->
    <select id="queryBatch" resultType="employee">
        select * from t_emp
            where emp_id in
            <foreach collection="ids" open="("  separator="," close=")" item="id">
                #{id}
            </foreach>
    </select>

<!--    int deleteBatch(@Param("ids") List<Integer> ids);-->
    <delete id="deleteBatch">
        delete from t_emp where id in
        <foreach collection="ids" open="(" close=")" item="id">
            #{id}
        </foreach>
    </delete>

<!--    int insertBatch(@Param("list") List<Employee> employeeList);-->
    <insert id="insertBatch">
        insert into t_emp (emp_name,emp_salary)
        values
        <foreach collection="list" separator="," item="employee">
            (#{employee.empName),#{employee.empSalary})
        </foreach>
    </insert>

<!--    int updateBatch(@Param("list") List<Employee> employeeList);-->
    <update id="updateBatch">
        <foreach collection="list" item="emp">
            update t_emp set emp_name =#{emp.empName},emp_salary = #{emp.Salary}
            where emp_id = #{emp.empId)
        </foreach>
    </update>

7、sql片段

1、作用

1、抽取重复的sql片段(类似封装)

2、用到\标签

3、\标签

2、例子

1、sql语句

<!--    List<Employee> queryBatch(@Param("ids") List<Integer> ids);-->

    <sql id="queryBatch11">
        select * from t_emp
    </sql>

    <select id="queryBatch1" resultType="employee">
        <include refid="queryBatch11"></include>
        where emp_id in
        <foreach collection="ids" open="("  separator="," close=")" item="id">
            #{id}
        </foreach>
    </select>
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇