• MyBatis


    MyBatis 是什么?

    MyBatis 是⼀款优秀的持久层框架,它⽀持⾃定义 SQL、存储过程以及高级映射。MyBatis 去除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老实 Java 对象)为数据库中的记录。

    简单来说 MyBatis 是更简单完成程序和数据库交互的工具,也就是更简单的操作和读取数据库工具

    为什么要学习 MyBatis?

    对于后端开发来说,程序是由以下两个重要的部分组成的:

    1.后端程序
    2. 数据库

    在这里插入图片描述

    而这两个重要的组成部分要通讯,就要依靠数据库连接工具,那数据库连接工具有哪些?比如之前我们学习的 JDBC,还有今天我们将要介绍的 MyBatis,那已经有了 JDBC 了,为什么还要学习MyBatis?这是因为 JDBC 的操作太繁琐了,JDBC 的操作流程:

    1.创建数据库连接池 DataSource
    2. 通过 DataSource 获取数据库连接 Connection
    3. 编写要执行带 ? 占位符的 SQL 语句
    4. 通过 Connection 及 SQL 创建操作命令对象 Statement
    5. 替换占位符:指定要替换的数据库字段类型,占位符索引及要替换的值
    6. 使⽤ Statement 执行 SQL 语句
    7. 查询操作:返回结果集 ResultSet,更新操作:返回更新的数量
    8. 处理结果集
    9. 释放资源

    操作流程可以看出,对于 JDBC 来说,整个操作非常的繁琐,我们不但要拼接每⼀个参数,而且还要按照模板代码的方式,⼀步步的操作数据库,并且在每次操作完,还要手动关闭连接等,而所有的这些操作步骤都需要在每个方法中重复书写

    MyBatis 给我们提供了更简单、更方便的操作数据库的方式

    MyBatis操作从0到1(单表)

    在MySQL数据库中,添加以下数据,方便后续操作案例:

    -- 创建数据库
    drop database if exists mycnblog;
    create database mycnblog DEFAULT CHARACTER SET utf8mb4;
    
    -- 使用数据数据
    use mycnblog;
    
    -- 创建表[用户表]
    drop table if exists  userinfo;
    create table userinfo(
        id int primary key auto_increment,
        username varchar(100) not null,
        password varchar(32) not null,
        photo varchar(500) default '',
        createtime datetime default now(),
        updatetime datetime default now(),
        `state` int default 1
    ) default charset 'utf8mb4';
    
    -- 创建文章表
    drop table if exists  articleinfo;
    create table articleinfo(
        id int primary key auto_increment,
        title varchar(100) not null,
        content text not null,
        createtime datetime default now(),
        updatetime datetime default now(),
        uid int not null,
        rcount int not null default 1,
        `state` int default 1
    )default charset 'utf8mb4';
    
    -- 创建视频表
    drop table if exists videoinfo;
    create table videoinfo(
      	vid int primary key,
      	`title` varchar(250),
      	`url` varchar(1000),
    		createtime datetime default now(),
    		updatetime datetime default now(),
      	uid int
    )default charset 'utf8mb4';
    
    -- 添加一个用户信息
    INSERT INTO `mycnblog`.`userinfo` (`id`, `username`, `password`, `photo`, `createtime`, `updatetime`, `state`) VALUES 
    (1, 'admin', 'admin', '', '2021-12-06 17:10:48', '2021-12-06 17:10:48', 1);
    
    -- 文章添加测试数据
    insert into articleinfo(title,content,uid)
        values('Java','Java正文',1);
        
    -- 添加视频
    insert into videoinfo(vid,title,url,uid) values(1,'java title','http://www.baidu.com',1);
    
    • 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
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    想要使用mybatis,首先在创建项目时,需要添加两个依赖:MyBatis FrameworkMySQL Driver,如果你的数据库不是MySQL,也需要添加对应的依赖

    在这里插入图片描述

    在这里插入图片描述

    项目创建好了,需要添加配置文件,我这里是添加了三个配置文件

    开发环境配置文件

    application-devel.yml

    # 配置数据库连接
    spring:
      datasource:
        url: jdbc:mysql://127.0.0.1:3306/mycnblog?characterEncoding=utf8
        username: root
        password: fl12345.0
        driver-class-name: com.mysql.cj.jdbc.Driver
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    生产环境配置文件

    application-prod.yml:因为没有生产环境,所以可以不用写,如果有,就可以写

    配置当前运行环境

    application.yml

    spring:
      profiles:
        active: devel
    
    # 配置 mybatis xml保存路径
    mybatis:
      mapper-locations: classpath:mybatis/**Mapper.xml # classpath表示根目录	
      # **Mapper.xml表示以**(通配符)开头的Mapper.xml文件,后续的数据库具体操作都是在**Mapper.xml中编写的,所以路径一定要指明清楚										
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    配置文件配置好后,就能够成功启动项目了,但为了业务的分层,还可以在 demo 下新建3个目录,它们分别是controller,mapper,model和service

    这里的 mapper 主要是用来存放数据查询时的接口的

    查询操作

    在 mapper 中添加一个接口 UserInfo

    @Mapper //加了注解,此时就变成了 mybatis 的接口
    public interface UserMapper {
    
        //根据用户 id 查询用户
        public UserInfo getUserById(@Param("id") Integer id);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    @Param(“id”) 表示 参数为 id 的字段在 xml 中的名字叫 id

    在目录 sr/main/resource 下,添加一个 mybatis 目录,并在这个目录下新建一个 UserMapper.xml,并将以下内容拷贝进去:

    
    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">    
    mapper>
    
    • 1
    • 2
    • 3
    • 4

    namespace 需要将 xml 文件和 interface 关联起来,它就一个路径,从 java 源代码这个目录开始

    现在需要实现 UserMapper 中的 getUserById() 方法
    以下内容放在

    <select id="getUserById" resultType="com.example.demo.model.UserInfo">
    	select * from userinfo where id=${id}
    select>
    
    • 1
    • 2
    • 3

    $也可以换成#,这两者有什么区别,后面会提到

    参数解析:

    id:表示要实现的接口中的具体方法名
    resultType:表示查询返回的类型,需要指明这类型来自哪个包下的哪个类,路径从 java 源代码这个目录开始

    在 service 中创建一个类 UserService:

    @Service
    public class UserService {
        //接口也能被注入,mybatis的接口会在运行时称为一个对象
        @Resource
        private UserMapper userMapper;
    
        public UserInfo getUserById(Integer id) {
            return userMapper.getUserById(id); 
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在 Controller 中添加一个 UserController 类:

    @RestController
    @RequestMapping("/user")
    public class UserController {
    
        @Autowired
        private UserService userService;
    
        public UserInfo getUserById(Integer id) {
            if (id == null) {
                return null;
            }
            return userService.getUserById(id);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    到目前为止,所以文件目录如下图:

    在这里插入图片描述

    运行项目,进行访问:

    在这里插入图片描述

    在这里插入图片描述

    首先前端通过 ajax 访问后端,ajax 请求先到达 Controller,经过参数验证后,再到达 Service, Service 决定调用哪些 Mapper。

    在项目运行的时候,Mybatis 会将 Interface 和 .xml 做一个关联,将里面的 sql 转换为原始的 sql,最终执行的时候,会调用 jdbc

    修改操作

    在 UserMapper 中添加一个新的方法声明:

    public int update(@Param("id") Integer id, @Param("username") String username);
    
    • 1

    @Param(“username”)最好添加上,“username” 要和 .xml中的#{username}对应,否则会导致参数找不到的问题,就会报错

    在 UserMapper.xml 添加修改用户 id 的sql:

    
    <update id="update">
    	update userinfo set username=#{username} where id=#{id}
    update>
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    如何生成单元测试–》

    生成对应的单元测试:

    @Test
    void update() {
        int result = userMapper.update(2, "fl");
        Assertions.assertEquals(1, result);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    进行测试:

    在这里插入图片描述

    删除操作

    在 UserMapper 中添加一个新的方法声明:

    public int del(@Param("id") Integer id);
    
    • 1

    在 UserMapper.xml 添加删除指定 id 用户的 sql:

    
    <delete id="del">
        delete from userinfo where id=#{id}
    delete>
    
    • 1
    • 2
    • 3
    • 4

    生成对应的单元测试:

    @Test
    void del() {
        int result = userMapper.del(1);
        System.out.println("受影响的行数为" + result);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    进行测试:

    在这里插入图片描述

    添加操作

    在 UserMapper 中添加一个新的方法声明:

    //添加用户,返回受影响的行数
    public int add(UserInfo userInfo);
    
    • 1
    • 2

    在 UserMapper.xml 添加对应的 sql:

    <insert id="add">
        insert into userinfo(username,password,photo)
        values(#{username},#{password},#{photo})
    insert>
    
    • 1
    • 2
    • 3
    • 4

    生成对应的单元测试:

    @Test
        void add() {
            UserInfo userInfo = new UserInfo();
            userInfo.setUsername("fl");
            userInfo.setPassword("123");
            userInfo.setPhoto("default.png");
            int result = userMapper.add(userInfo);
            System.out.println("受影响的行数" + result);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    添加操作默认情况下返回的是受影响的行数

    特殊的添加:返回⾃增 id
    默认情况下返回的是受影响的行号,如果想要返回自增 id

    在 UserMapper 中添加一个新的方法声明:

    //添加用户,返回受影响的行数和自增id
    public int addGetId(UserInfo userInfo);
    
    • 1
    • 2

    在 UserMapper.xml 添加对应的 sql:

    
    <insert id="addGetId" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
        insert into userinfo(username,password,photo)
        values(#{username},#{password},#{photo})
    insert>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • useGeneratedKeys:这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的自动递增字段),默认值:false。
    • keyColumn:设置生成键值在表中的列名,在某些数据库(像 PostgreSQL)中,当主键列不是表中的第⼀列的时候,是必须设置的。如果⽣成列不止⼀个,可以用逗号分隔多个属性名称。
    • keyProperty:指定能够唯⼀识别对象的属性,MyBatis 会使用 getGeneratedKeys 的返回值或 insert 语句的 selectKey 子元素设置它的值,默认值:未设置(unset)。如果生成列不止⼀个,可以用逗号分隔多个属性名称

    生成对应的单元测试:

    @Test
    void addGetId() {
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("fl");
        userInfo.setPassword("123");
        userInfo.setPhoto("default.png");
        System.out.println("添加之前 user id:" + userInfo.getId());
        int result = userMapper.addGetId(userInfo);
        System.out.println("受影响的行数" + result);
        System.out.println("添加之后 user id:" + userInfo.getId());
        Assertions.assertEquals(1, result);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    进行测试:

    在这里插入图片描述

    占位符 #{} 和 ${}的区别(针对int类型的参数)

    先使用方法 getUserById() 进行测试

    查询sql:

    <select id="getUserById" resultType="com.example.demo.model.UserInfo">
        select * from userinfo where id=#{id}
    select>
    
    • 1
    • 2
    • 3

    测试方法:

    @Test
        void getUserById() {
            UserInfo userInfo = userMapper.getUserById(1);
            log.info("用户信息:" + userInfo);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    使用 #{ }占位符,相当于预编译处理

    预编译处理是指:MyBatis 在处理#{}时,会将 SQL 中的 #{} 替换为?号,使用 PreparedStatement 的
    set 方法来赋值。

    将 #{id} 改为 ${id} 后,再次进行测试

    在这里插入图片描述

    可以发现占位符 ${ } 使用的是直接替换
    直接替换:是MyBatis 在处理 ${ } 时,就是把 ${ } 替换成变量的值

    根据上述结果,可以知道,查询的类型是 int 类型,使用 #{ } 和使用 ${ } 产生的结果是一样的,如果查询类型是 String 呢?

    比如根据全名查询用户对象(非模糊查询)

    在 UserMapper 中添加一个新的方法声明:

    public UserInfo getUserByFullName(@Param("username") String username);
    
    • 1

    在 UserMapper.xml 添加删除指定 id 用户的 sql:

    
    <select id="getUserByFullName" resultType="com.example.demo.model.UserInfo">
        select * from userinfo where username=#{username}
    select>
    
    • 1
    • 2
    • 3
    • 4

    生成对应的单元测试:

    @Test
        void getUserByFullName() {
            UserInfo userInfo = userMapper.getUserByFullName("张三");
            log.info("用户信息:" + userInfo);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    测试结果:

    在这里插入图片描述

    此时,将 #{username} 换成 ${username}后,再次进行测试

    在这里插入图片描述

    结果就报错了。原因是 ${username} 只是进行了简单的替换,并没有加单引号

    再看一个例子:获取列表,根据创建时间进行正序或倒序排序

    在 UserMapper 中添加一个新的方法声明:

    public List<UserInfo> getOrderList(@Param("order") String order);
    
    • 1

    在 UserMapper.xml 添加删除指定 id 用户的 sql:

    <select id="getOrderList" resultType="com.example.demo.model.UserInfo">
        select * from userinfo order by createtime ${order}
    select>
    
    • 1
    • 2
    • 3

    生成对应的单元测试:

    @Test
    void getOrderList() {
        List<UserInfo> list = userMapper.getOrderList("desc");
        log.info("列表:" + list);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    测试结果:

    在这里插入图片描述

    并没有什么问题。此时,将 #{username} 换成 ${username}后,再次进行测试

    在这里插入图片描述

    结果产生了错误,为什么呢?
    因为最终执行的sql是:

    select * from userinfo order by createtime 'desc'
    
    • 1

    所以使用 #{ } 时,认为传递的参数都是 value,而非 sql 中关键字

    注意:使用${ }存在SQL注入问题

    当不得不使用 ${ } 时,那么一定要在业务代码中,对传递的值进行安全效验

    like查询

    在 UserMapper 中添加一个新的方法声明:

    public List<UserInfo> getListByName(@Param("username") String username);
    
    • 1

    在 UserMapper.xml 添加删除指定 id 用户的 sql:

    <select id="getListByName" resultType="com.example.demo.model.UserInfo">
        select * from userinfo where username like '%#{username}%'
    select>
    
    • 1
    • 2
    • 3

    生成对应的单元测试:

    @Test
    void getListByName() {
        String username = "a";
        List<UserInfo> list = userMapper.getListByName(username);
        log.info("" + list);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    进行测试:

    在这里插入图片描述

    结果报错了,原因就是最终生成的sql是不合法的

    select * from userinfo where username like '%'f'%'
    
    • 1

    因为使用的#{ },生成sql时会自动添加单引号,为了不让它产生单引号,可以使用${ },再次测试

    在这里插入图片描述

    虽然测试通过了,但是对于使用 ${ } 会存在sql注入问题,因此我们需要对参数的有效性进行校验,此时问题又来了,username 无法穷举

    对于上述这个情况,我们可以采用 mysql 内置的方法 concat 就能解决

    对 UserMapper.xml 中的 sql 进行修改:

    <select id="getListByName" resultType="com.example.demo.model.UserInfo">
        select * from userinfo where username like concat('%',#{username},'%')
    </select>
    
    • 1
    • 2
    • 3

    再次进行测试:

    在这里插入图片描述

    多表查询

    resultMap 和 resultType

    当表中字段名和实体中的属性名不一致时,可以使用 resultMap 解决这个问题

    在这里插入图片描述

    mapper.xml 代码如下:

    <resultMap id="BaseMap" type="com.example.demo.model.UserInfo">
        
        <id column="id" property="id">id>
        
        <result column="username" property="name">result>
    resultMap>
    
    
    
    <select id="getUserById" resultMap="BaseMap">
        select * from userinfo where id=${id}
    select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    column 是数据库中表的字段名,property 是实体中的属性名
    表示将数据库中表中的 id 和 实体中的 id 进行映射

    测试结果:

    在这里插入图片描述

    在这里插入图片描述

    一对一的表映射

    ⼀对⼀映射要使用 标签,具体实现如下(⼀篇文章只对应⼀个作者)

    最开始,我们已经建了一个 articleinfo 表:

    在这里插入图片描述

    在 model 层中新建一个 ArticleInfo 类:

    @Data
    public class ArticleInfo {
        private int id;
        private String title;
        private String content;
        private String createtime;
        private String updatetime;
        private int uid;
        private int rcount;
        private int state;
        private UserInfo userInfo;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在 mapper 层中新建一个 UserMapper 接口:

    @Mapper
    public interface UserMapper {
    	//根据文章 id 获取文章
        public ArticleInfo getArticleById(@Param("id") Integer id);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在 mybatis 中新建一个 ArticleMapper.xml:

    
    DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="com.example.demo.mapper.ArticleMapper">
        <resultMap id="BaseMap" type="com.example.demo.model.ArticleInfo">
            <id column="id" property="id">id>
            <result column="title" property="title">result>
            <result column="content" property="content">result>
            <result column="createtime" property="createtime">result>
            <result column="updatetime" property="updatetime">result>
            <result column="uid" property="uid">result>
            <result column="rcount" property="rcount">result>
            <result column="state" property="state">result>
            <association property="userInfo" resultMap="com.example.demo.mapper.UserMapper.BaseMap"
            columnPrefix="u_">association>
        resultMap>
    
        <select id="getArticleById" resultMap="BaseMap">
            select a.*, u.id u_id, u.username u_username, u.password u_password
            from articleinfo a
            left join userinfo u
            on a.uid=u.id
            where a.id=#{id}
        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

    生成单元测试代码:

    @SpringBootTest
    @Slf4j
    class ArticleMapperTest {
    
        @Resource
        private ArticleMapper articleMapper;
    
        @Test
        void getArticleById() {
            ArticleInfo articleInfo = articleMapper.getArticleById(1);
            log.info("文章详情:" + articleInfo);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    进行测试:

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    以上使用 标签,表示⼀对⼀的结果映射:
    property 属性:指定 Article 中对应的属性,即用户。
    resultMap 属性:指定关联的结果集映射,将基于该映射配置来组织用户数据。
    columnPrefix 属性:绑定⼀对⼀对象时,是通过columnPrefix+association.resultMap.column 来映射结果集字段。
    association.resultMap.column是指 标签中 resultMap属性,对应的结果集映射中,column字段
    注意事项:column不能省略

    当两个实体都有相同的属性时,默认查询时,后者会覆盖前者,因此需要用 columnPrefix 对其进行起别名

    一对多的表映射

    ⼀对多需要使用 标签,用法和 相同

    对 model 层中的 UserInfo类进行修改:

    @Data
    public class UserInfo {
        private Integer id;
        private String name;
        private String password;
        private String photo;
        private String createtime;
        private String updatetime;
        private int state;
        private List<ArticleInfo> artlist;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在 UserMapper 中添加一个新的方法声明:

    //根据用户id查询用户及用户发表的所有文章
    public UserInfo getUserAndArticleByid(@Param("uid") Integer uid);
    
    • 1
    • 2

    在 UserMapper.xml 添加对应的 sql:

    <select id="getUserAndArticleByid" resultMap="BaseMap">
        select u.*,a.id a_id,a.title a_title,a.content a_content,a.createtime a_createtime,a.updatetime a_updatetime
        from userinfo u
        left join articleinfo a
        on u.id=a.uid where u.id=#{uid}
    select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    生成对应的单元测试:

    @Test
    void getUserAndArticleByid() {
        UserInfo userInfo = userMapper.getUserAndArticleByid(1);
        log.info("用户详情:" + userInfo);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    测试结果:

    在这里插入图片描述

    动态SQL

    动态 SQL 是 MyBatis 的强大特性之一

    if 标签

    if 标签的主要作用:

    判断一个参数是否有值的,如果没值,那么就会隐藏 if 中的 sql

    就像我们在填写一些注册信息的时候,有些项可以填也可以不填,有些就是必须要填

    标签语法:

    在这里插入图片描述

    在 UserMapper中新建一个方法:

    // 添加用户,添加用户时 photo是非必传参数
    public int add2(UserInfo userInfo);
    
    • 1
    • 2

    在 UserMapper.xml 添加对应的 sql:

    
    <insert id="add2">
        insert into userinfo(username,password
        <if test="photo!=null">
            ,photo
        if>
        ) values(#{name},#{password}
        <if test="photo!=null">
            ,#{photo}
        if>
        )
    insert>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    不加 photo 的进行单元测试:

    @Test
    void add2() {
        UserInfo userInfo = new UserInfo();
        userInfo.setName("李四");
        userInfo.setPassword("123");
        int result = userMapper.add2(userInfo);
        log.info("新用户结果:" + result);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    添加 photo 的进行单元测试:

    @Test
    void add2() {
        UserInfo userInfo = new UserInfo();
        userInfo.setName("李四");
        userInfo.setPassword("123");
        userInfo.setPhoto("default.png");
        int result = userMapper.add2(userInfo);
        log.info("新用户结果:" + result);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    最终数据库的结果:

    在这里插入图片描述

    trim 标签

    trim 标签的主要的作用:

    去除SQL语句前后多余的某个字符的

    标签语法:

    在这里插入图片描述

    标签中有如下属性:
    prefix:表示整个语句块,以prefix的值作为前缀
    suffix:表示整个语句块,以suffix的值作为后缀
    prefixOverrides:表示整个语句块要去除掉的前缀
    suffixOverrides:表示整个语句块要去除掉的后缀

    在 UserMapper中新建一个方法:

    // 添加用户,其中 username、password、photo 都是非必传参数,
    // 但至少会传递一个参数
    public int add3(UserInfo userInfo);
    
    • 1
    • 2
    • 3

    在 UserMapper.xml 添加对应的 sql:

    
    
    <insert id="add3">
        insert into userinfo
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="name!=null">
                username,
            if>
            <if test="password!=null">
                password,
            if>
            <if test="photo!=null">
                photo
            if>
        trim>
        values
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="name!=null">
                #{name},
            if>
            <if test="password!=null">
                #{password},
            if>
            <if test="photo!=null">
                #{photo}
            if>
        trim>
    insert>
    
    • 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
    • 27
    • 28

    生成对应的单元测试:

    @Test
    void add3() {
        UserInfo userInfo = new UserInfo();
        userInfo.setName("王五");
        userInfo.setPassword("123");
        userInfo.setPhoto("123.png");
        int result = userMapper.add3(userInfo);
        log.info("添加用户的结果:" + result);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    测试结果:

    在这里插入图片描述

    where 标签

    主要作用:

    实现查询中的where sql替换的,它可以实现如果没有任何的查询条件,那么它可以隐藏查询中的where sql, 但如果存在查询条件,那么会生成where 的sql 查询。并且使用where 标签可以自动的去除最前面一个and字符。

    在测试之间,先要把表中的数据删除掉,只留一条数据
    在这里插入图片描述

    使用 UserMapper 中的方法:

    // 根据用户 id 查询用户
    public UserInfo getUserById(@Param("id") Integer id);
    
    • 1
    • 2

    修改 UserMapper.xml 中对一个的 sql:

    
    <select id="getUserById" resultMap="BaseMap">
        select * from userinfo
        <where>
            <if test="id!=null">
                id=#{id}
            if>
        where>
    select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    对应的单元测试:

    @Test
    void getUserById() {
        UserInfo userInfo = userMapper.getUserById(1);
        log.info("用户信息:" + userInfo);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    测试结果:

    在这里插入图片描述

    如果我们传null,再进行测试:

    在这里插入图片描述

    加上 and:

    在这里插入图片描述

    测试结果:

    在这里插入图片描述

    注意: and 在前面不能在后面

    在这里插入图片描述

    测试结果:

    在这里插入图片描述

    set 标签

    set 标签的主要作用:

    进行修改操作时,配合if 来处理非必传传输的,它的特点是会自动去除最后一个英文逗号

    标签语法:

    在这里插入图片描述

    初始数据:

    在这里插入图片描述

    在 UserMapper中新建一个方法:

    //修改用户
    public int update2(UserInfo userInfo);
    
    • 1
    • 2

    在 UserMapper.xml 添加对应的 sql:

    <update id="update2">
        update userinfo
        <set>
            <if test="name!=null">
                username=#{name},
            if>
            <if test="password!=null">
                password=#{password},
            if>
            <if test="photo!=null">
                photo=#{photo}
            if>
        set>
        where id=#{id}
    update>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    生成对应的单元测试:

    @Test
    void update2() {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setName("赵六");
        int result = userMapper.update2(userInfo);
        log.info("update2 修改的结果为:" + result);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    测试结果:

    在这里插入图片描述

    数据库中的最终结果:

    在这里插入图片描述

    foreach 标签

    foreach 标签主要作用:

    对集合进行循环

    foreach 标签中主要属性介绍:

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

    在 UserMapper中新建一个方法:

    //根据用户id的集合进行删除操作
    int delIds(List<Integer> list);
    
    • 1
    • 2

    在 UserMapper.xml 添加对应的 sql:

    <delete id="delIds">
        delete from userinfo where id in
        <foreach collection="ids" open="(" close=")" item="id" separator=",">
            #{id}
        foreach>
    delete>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    数据库中的原始数据:

    在这里插入图片描述

    生成对应的单元测试:

    @Test
    void delIds() {
        List<Integer> list = new ArrayList<>();
        list.add(8);
        list.add(9);
        list.add(10);
        int result = userMapper.delIds(list);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    测试结果:

    在这里插入图片描述

    数据库中的最终结果:

    在这里插入图片描述

  • 相关阅读:
    怎么把两个PDF合并成一个?建议收藏这些合并的方法
    MySQL read 查询语句5 日期时间相关函数
    全国世界城市列表API接口,免费好用
    ROS1云课→09功能包小定制(CLI命令行接口)
    Vue2+SpringBoot实现数据导出到csv文件并下载
    【课程作业】基于Java的宠物领养管理网站系统源码
    MySql 数据库初始化,创建用户,创建数据库,授权
    C++面试八股文:什么是空指针/野指针/悬垂指针?
    华为云云服务器评测|基于华为云云耀云服务器L实例开展性能评测,例如 MySQL、Clickhouse、Elasticsearch等等
    MySQL知识点总结(五)——锁
  • 原文地址:https://blog.csdn.net/qq_56044032/article/details/128120146