• 【MyBatis】动态SQL


    本文已收录于专栏
    ⭐️ 《MyBatis》⭐️

    MyBatis

    MyBatis 是一款优秀的持久层框架

    MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集的过程

    MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 实体类 【Plain Old Java Objects,普通的 Java对象】映射成数据库中的记录。

    映射文件概述

    在这里插入图片描述

    常用配置

    environments标签

    数据源环境配置标签

    数据库环境的配置,支持多环境配置

    事务管理器(transactionManager)类型有两种:

        • JDBC:这个配置就是直接使用了JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作用域。
    
        • MANAGED:这个配置几乎没做什么。它从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如JEE 应用服务器的上下文)。 默认情况下它会关闭连接,然而一些容器并不希望这样,因此需要将 closeConnection 属性设置 为 false 来阻止它默认的关闭行为。
    
    • 1
    • 2
    • 3

    数据源(dataSource)类型有三种:

        • UNPOOLED:这个数据源的实现只是每次被请求时打开和关闭连接。
    
        • POOLED:这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来。
    
        • JNDI:这个数据源的实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置 一个 JNDI 上下文的引用
    
    • 1
    • 2
    • 3
    • 4
    • 5

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3FQINKqN-1660785250531)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220815093834929.png)]

    mapper标签

    加载映射配置

    该标签的作用是加载映射的,加载方式有如下几种:

    • 使用相对于类路径的资源引用,例如:


    • 使用完全限定资源定位符(URL),例如:


    • 使用映射器接口实现类的完全限定类名,例如:


    • 将包内的映射器接口实现全部注册为映射器,例如:

    Properties标签

    该标签可以加载外部的properties文件

    ​ 实际开发中,习惯将数据源的配置信息单独抽取成一个properties文件,该标签可以加载额外配置的properties文件(像web阶段抽取一样)

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JgLr5W5g-1660785250532)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220815094208642.png)]

    typeAliases标签

    设置类型别名

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5wHsPHCm-1660785250533)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220815094057280.png)]

    代理开发

    采用 Mybatis 的代理开发方式实现 DAO 层的开发,这种方式是我们后面进入企业的主流。 Mapper 接口开发方法只需要程序员编写Mapper 接口(相当于Dao 接口),由Mybatis 框架根据接口定义创建接 口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。
    
    • 1

    Mapper 接口开发需要遵循以下规范:

        1、 Mapper.xml文件中的namespace与mapper接口的全限定名相同
    
        2、 Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
    
        3、 Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同
    
        4、 Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    对应关系图解

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ycZTwNNZ-1660785250534)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220815094516358.png)]

    开发步骤

    ①编写BrandMapper接口

    ②进行mapper文件的相应配置(要遵守规范)

    ③测试用例

    ①编写BrandMapper接口

    public interface BrandMapper {
       //实现操作:查询所有
       List<Brand> selectAll();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    ②进行mapper文件的相应配置(要遵守规范)

    
    DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace = "com.spellbind.mapper.BrandMapper">
        
        <resultMap id="brandResultMap" type="brand">
            <result column="brand_name" property="brandName">result>
            <result column="company_name" property="companyName">result>
        resultMap>
    
        
        <select id="selectAll" resultMap="brandResultMap">
            select * from tb_brand;
        select>
    
    mapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    ③测试代理方式:

    @Test//查看所有
    public void testSelectAll() throws Exception {
        //1.加载mybatis的核心配置文件,获取 SqlSessionFactory
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //2.获取Sqlsession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //3.获取Mapper 接口的代理对象
        BrandMapper brandmapper = sqlSession.getMapper(BrandMapper.class);
        //4.执行方法
        List<Brand> brands = brandmapper.selectAll();
    
        System.out.println(brands);
        //5.关闭资源
        sqlSession.close();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    * 参数占位符: 
    1.#{}:会将其替换为 ?,为了防止SQL注入
    2.${}:直接拼接 sql,存在SQL注入问题
    3.使用时机:
        * 参数传递时:#{}
        * 表名或者列名不固定的情况下:${}会存在SQL注入问题
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    动态SQL

    在传统的JDBC的操作中书写SQL语句是非常容易出错的,而Mybatis的动态SQL的出现则很巧妙的解决了这一问题。

    其通过 if, choose, when, otherwise, trim, where, set, foreach 标签,可组合成非常灵活的SQL语句,从而大大提高开发效率。

    if

    Mybatis提供了 if 标签,可以实现针对多个参数进行可选搜索。

    test:填入的是能否进行下面SQL语句的判断表达式

    <select id="findUserById" resultType="users">
        select * from users 
        where 
            <if test="id != null">
                   id > #{id}
            if>
        	<if test="name != null">
            AND name like #{title}
    select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    执行的SQL语句是:

    select * from users where id > 'xx' and name like 'xxx'
    
    • 1

    但这样会出现一系列语法问题。

    当 id 为空时,and 会直接与 where相连

    select * from users where and name like 'xxx'
    
    • 1

    当 id 和 age 都为空时,where 后面就没有了语句。

    select * from users where
    
    • 1

    很显然,这样会造成运行错误

    那么,如何解决上面所说的问题呢?mybatis给出了****元素。

    where

    <select id="findUserById" resultType="users">
        select * from users 
        <where>
            <if test="id != null">
                   id > #{id}
            if>
        	<if test="name != null">
            AND name like #{name}
        where>
    select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。

    而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。

    set

    <update id="updateUser" parameterType="com.dy.entity.User">
        update user set 
            <if test="name != null">
                name = #{name},
            if> 
            <if test="password != null">
                password = #{password},
            if> 
            <if test="age != null">
                age = #{age}
            if> 
            <where>
                <if test="id != null">
                    id = #{id}
                if>
                and deleteFlag = 0;
            where>
    update>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    从上面这里我们可以发现,如果只有 name 不为空时,SQL语句则变为:

    update set name = #{name}, where deleteFlag = 0;
    
    • 1

    此时 name 后面的逗号 则会导致语法错误。

    我们需要用mybatis为我们提供的set 标签来解决这个问题。

    <update id="updateUser" parameterType="com.dy.entity.User">
        update user
            <set>
                <if test="name != null">name = #{name},if> 
                <if test="password != null">password = #{password},if> 
                <if test="age != null">age = #{age},if> 
            set>
            <where>
                <if test="id != null">
                    id = #{id}
                if>
                and deleteFlag = 0;
            where>
    update>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    foreach

    当接收多个参数时,一个一个写显然过于麻烦,mybatis中的foreach标签可以帮助我们直接遍历数组.

    动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。

    属性描述
    collection表示集合的名称,默认名为 array,可以使用@Param注解指定, 该参数为必选
    item表示本次迭代获取的元素,若collection为List、Set或者数组,则表示其中的元素;若collection为map,则代表key-value的value,该参数为必选
    open表示该语句以什么开始,最常用的是左括弧’(’,注意:mybatis会将该字符拼接到整体的sql语句之前,并且只拼接一次,该参数为可选项
    close表示该语句以什么结束,最常用的是右括弧’)’,注意:mybatis会将该字符拼接到整体的sql语句之后,该参数为可选项
    separatormybatis会在每次迭代后给sql语句append上separator属性指定的字符,该参数为可选项
    index在list、Set和数组中,index表示当前迭代的位置,在map中,index代指是元素的key,该参数是可选项。
    <select id="getBlogListByIds" parameterType="map" resultType="com.company.org.pojo.Blog">
        select * from blog
        <where>
            id in
            <foreach collection="ids" item="id" open="(" separator="," close=")">
               #{id}
            foreach>
        where>
    select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    上面这个例子的作用是,查询id在ids(列表)中的博客。

    相当于sql语句:

    select * from blog where id IN (116012859,117374430,118058442)
    
    • 1

    完结散花

    ok以上就是对 动态SQL 的全部讲解啦,很感谢你能看到这儿。如果有遗漏、错误或者有更加通俗易懂的讲解,欢迎小伙伴私信我,我后期再补充完善。

    参考文献

    https://blog.csdn.net/qq_33369905

  • 相关阅读:
    PostgreSQL创建表基本语法
    spring-boot-starter-data-redis 引发的一系列惨案
    登录功能的实现(包括前后端)
    linux 下代码检查工具部署使用
    C语言之递归
    24位ADC芯片AD7190讲解和代码编写(基于STM32模板的硬件软件SPI)
    Golang 区块链开发指南
    在Linux上安装Oracle 数据库 11g (含静默方式安装)
    测试踩坑 - 当已有接口(或数据库表中)新增字段时,都需要注意哪些测试点?
    基于YOLOv5的目标检测系统详解(附MATLAB GUI版代码)
  • 原文地址:https://blog.csdn.net/m0_66139206/article/details/126398679