• Mybatis 查询数据库


    1. MyBatis 是什么?

    MyBatis 是一个优秀的 ORM(对象关系映射) 持久层框架.

    1. 它⽀持⾃定义 SQL、存储过程以及⾼级映射。
    2. MyBatis 去除了⼏乎所有的 JDBC 代码以及设置参数和获取结果集的⼯作。
    3. MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接⼝和 Java POJO(Plain Old Java Objects,普通⽼式 Java 对象)为数据库中的记录。

    简单来说 MyBatis 是更简单完成程序和数据库交互的⼯具,也就是更简单的操作和读取数据库⼯具,特点就是很灵活.

    我们学习 MyBatis 主要学习两部分:
    1. 配置 MyBatis 开发环境
    2. 使用 MyBatis 模式和语法操作数据库

    2. 创建 MyBatis 项目

    2.1 准备工作,创建数据库和数据表

    mybatis 测试数据库:

    -- 创建数据库
    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

    注: MySQL 5.7 以下版本 需要去掉 default now()
    在这里插入图片描述

    2.2 添加 MyBatis 相关依赖

    在这里插入图片描述

    添加完后不要急着启动项目测试:
    在这里插入图片描述

    因为我们还没有连接数据库,他是找不到路径的

    2.3 配置数据库连接字符串 和 MyBatis(保存的 XML 的目录)

    2.3.1 配置数据库的连接信息

    这里一般我们会用多个配置文件,以便之后在多个平台运行(最少一般都会有两个)
    在这里插入图片描述

    像这种常用的,自己可以把它保存在能够经常拿到的地方,下次直接粘贴就好了.

    # 配置数据库连接
    spring:
      datasource:
        url: jdbc:mysql://127.0.0.1:3306/mycnblog?characterEncoding=utf8
        username: 你的用户名
        password: 你的密码
        driver-class-name: com.mysql.cj.jdbc.Driver
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    # 当前运行的环境 (配置文件)
    spring:
      profiles:
        active: dev
    
    • 1
    • 2
    • 3
    • 4

    2.3.2 配置 MyBatis 的 XML 保存路径

    # 配置 MyBatis xml 保存路径
    mybatis:
      mapper-locations: classpath:mybatis/**Mapper.xml
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    2.4 使用 MyBatis 的操作模式操作数据库

    我们可以先看一下 MyBatis 整体流程:
    在这里插入图片描述在这里插入图片描述

    2.4.1 添加代码

    提前创好对应的包:
    在这里插入图片描述

    1. model 包下添加实体类
    对应数据库添加:

    import lombok.Data;
    
    /**
     * 用户实体类
     */
    @Data
    public class UserInfo {
        private Integer id;
        private String username;
        private String password;
        private String photo;
        private String createtime;
        private String updatetime;
        private int state;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    2. 在 mapper 包下定义接口(普通的接口)

    import com.example.demo.model.UserInfo;
    import org.apache.ibatis.annotations.Mapper;
    
    @Mapper //添加后才能跟 xml 文件对应起来
    public interface UserMapper {
        //根据 id 查询用户
        public UserInfo getUserById(@Param("id") Integer id);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3. 创建 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
    • 5

    在 resources 的 mybatis 底下新建 UserMapper.xml:(xml 里的名字建议跟 mapper 包下的名字对应一样,这样容易我们观察)

    在这里插入图片描述

    MyBatis 执行过程:
    在这里插入图片描述

    MyBatis 是基于 JDBC 的

    4. 添加 Service 层代码

    import com.example.demo.mapper.UserMapper;
    import com.example.demo.model.UserInfo;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    
    @Service
    public class UserService {
    
        @Resource
        private UserMapper userMapper;
    
        public UserInfo getUserById(Integer id) {
            return userMapper.getUserById(id);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    5. 添加 Controller 层代码

    import com.example.demo.model.UserInfo;
    import com.example.demo.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @RequestMapping("/user")
    public class UserController {
    
        @Autowired
        private UserService userService;
    
        @RequestMapping("/getuserbyid")
        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
    • 15
    • 16
    • 17
    • 18
    • 19

    在这里插入图片描述

    2.5 测试数据

    在这里插入图片描述

    2.6 添加插件 MyBatisX

    左侧出现的小鸟是我添加的插件,点击小鸟他会自动帮我们找到对应的方法,非常的方便,可查
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    2.7 添加日志文件

    我们可以添加日志文件以便于我们操作之后排查错误

    # 开启 MyBatis SQL 打印
    logging:
      level:
        com:
          example:
            demo: debug
    mybatis:
      configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述
    在这里插入图片描述

    3. MyBatis 增删改查

    3.1 增添操作

    1. 在 mapper (interface) 添加增添方法声明

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

    2. 在 xml 中添加 < insert >标签和增添 sql 编写

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

    在这里插入图片描述

    3. service 层

    public int add(UserInfo userInfo){
            return userMapper.add(userInfo);
        }
    
    • 1
    • 2
    • 3

    4. controller 层

    @RequestMapping("/add")
        public int add(UserInfo userInfo){
            userInfo.setUsername("张三");
            userInfo.setPassword("123");
            userInfo.setPhoto("default.png");
            return userService.add(userInfo);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    5. 测试
    在这里插入图片描述在这里插入图片描述

    3.2 删除操作

    1. 在 mapper(interface) 里面添加删除的代码声明

     // 删除方法
        public int del(@Param("id") Integer id);
    
    • 1
    • 2

    2. 在 xml 中添加 < delete >标签和删除 sql 编写

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

    在这里插入图片描述

    3. service 层

     public int del(Integer id){
            return userMapper.del(id);
        }
    
    • 1
    • 2
    • 3

    4. controller 层

     @RequestMapping("/del")
        public int del(Integer id){
            return userService.del(id);
        }
    
    • 1
    • 2
    • 3
    • 4

    5. 测试
    在这里插入图片描述
    在这里插入图片描述

    3.3 修改操作

    1. 在 mapper(interface) 里面添加修改的代码声明

    // 修改方法【根据id修改名称】
        public int update(@Param("id") Integer id,
                          @Param("username") String username);
    
    • 1
    • 2
    • 3

    2. 在 xml 中添加 < update >标签和修改 sql 编写

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

    3. service 层

    public int update(Integer id,String username){
            return userMapper.update(id,username);
        }
    
    • 1
    • 2
    • 3

    4. controller 层

    @RequestMapping("/update")
        public int update(Integer id,String username){
            return userService.update(id,username);
        }
    
    • 1
    • 2
    • 3
    • 4

    5. 测试
    在这里插入图片描述在这里插入图片描述

    3.4 查找操作

    1. 在 mapper(interface) 里面添加查找的代码声明

    // 根据用户名来查询用户
        public UserInfo getUserByUsername(@Param("username") String username);
    
    • 1
    • 2

    一般是根据 id 来查找,因为用户名也可能重复

    2. 在 xml 中添加 < select >标签和查找 sql 编写

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

    3. service 层

    public UserInfo getUserByUsername(String username){
            return userMapper.getUserByUsername(username);
        }
    
    • 1
    • 2
    • 3

    4. controller 层

    @RequestMapping("/getuserbyusername")
        public UserInfo getUserById(String username){
            if(username == null) return null;
            return userService.getUserByUsername(username);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    5. 测试
    在这里插入图片描述

    3.5 汇总

    1. controller 层
    在这里插入图片描述
    2. mapper 层
    在这里插入图片描述

    3. model 层
    在这里插入图片描述

    4. service 层
    在这里插入图片描述

    5. XML 文件
    在这里插入图片描述

    我们发现了执行这些操作以后他是会"污染"我们的数据库的,那么如果我们只是想单纯的测试代码的正确性,这个时候就可以使用SpringBoot单元测试

    4. SpringBoot单元测试

    4.1 单元测试优点

    1. 可以非常简单,直观,快速的测试某一个功能是否正确
    2. 使用单元测试可以帮我们在打包的时候,发现一些问题,因为在打包之前,所有的单元测试必须通过,否则不能打包成功
    3. 使用单元测试,在测试功能的时候,可以不污染连接的数据库,也就是可以不对数据库进行任何改变的情况下,进行测试功能

    4.2 单元测试的实现

    4.2.1 准备工作: 确认项目中已经内置了测试框架

    在这里插入图片描述

    4.2.2 生成单元测试的类

    在 mapper 包下:
    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述

    4.2.3 配置单元测试的类添加 @SpringBootTest 注解,添加单元测试的业务代码

    1. 添加注解
    在这里插入图片描述

    2.添加单元测试的业务代码

    在这里插入图片描述
    在这里插入图片描述

    4.3 简单断言说明

    在这里插入图片描述

    断⾔:如果断⾔失败,则后⾯的代码都不会执⾏。

    4.4 添加 @Transactional 注解执行回滚事务

    我现在的数据库
    在这里插入图片描述

    执行修改操作:
    在这里插入图片描述

    修改成功:
    在这里插入图片描述

    在观察原数据库并没发生改变:
    在这里插入图片描述

    执行删除操作:
    在这里插入图片描述

    删除成功:
    在这里插入图片描述

    观察原数据库也没发生改变:
    在这里插入图片描述

    相关代码:

    import com.example.demo.model.UserInfo;
    import org.junit.jupiter.api.Assertions;
    import org.junit.jupiter.api.Test;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.transaction.annotation.Transactional;
    
    import javax.annotation.Resource;
    
    import static org.junit.jupiter.api.Assertions.*;
    
    @SpringBootTest
    class UserMapperTest {
    
        @Resource
        private UserMapper userMapper;
    
        @Test
        void getUserById() {
            UserInfo userInfo = userMapper.getUserById(1);
            System.out.println(userInfo);
        }
    
        // 在单元测试中添加此注解,表示在方法执行完之后回滚事务
        @Transactional
        @Test
        void update() {
            int result = userMapper.update(2, "张三");
            Assertions.assertEquals(1, result);
        }
    
        @Transactional
        @Test
        void del() {
            int result = userMapper.del(2);
            System.out.println("受影响的行数:" + result);
            Assertions.assertEquals(1, result);
        }
    
        @Transactional
        @Test
        void add() {
            UserInfo userInfo = new UserInfo();
            userInfo.setUsername("王五");
            userInfo.setPassword("123");
            userInfo.setPhoto("default.png");
            int result = userMapper.add(userInfo);
            System.out.println("添加的结果:" + result);
            Assertions.assertEquals(1, result);
        }
    }
    
    • 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

    4.5 返回自增 id

    我们不仅想看到受影响的行数,还想看到修改后的 id

    1. mapper层接口:

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

    2. XML 文件:

     
        <insert id="addGetId" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
            insert into userinfo(username,password,photo) values(#{username},#{password},#{photo})
        insert>
    
    • 1
    • 2
    • 3
    • 4

    useGeneratedKeys:这会令 MyBatis 使⽤ JDBC 的 getGeneratedKeys ⽅法来取出由数据库内部⽣成的主键(⽐如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的⾃动递增字段),默认值:false。
    keyColumn:设置⽣成键值在表中的列名,在某些数据库(像 PostgreSQL)中,当主键列不是表中的第⼀列的时候,是必须设置的。如果⽣成列不⽌⼀个,可以⽤逗号分隔多个属性名称。
    keyProperty:指定能够唯⼀识别对象的属性,MyBatis 会使⽤ getGeneratedKeys 的返回值或 insert 语句的 selectKey ⼦元素设置它的值,默认值:未设置(unset)。如果⽣成列不⽌⼀个,可以⽤逗号分隔多个属性名称

    3. 单元测试代码:

    //    @Transactional
        @Test
        void addGetId() {
            UserInfo userInfo = new UserInfo();
            userInfo.setUsername("老六");
            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
    • 13

    注释掉了回滚:
    在这里插入图片描述
    在这里插入图片描述

    4.6 一些查询操作

    4.6.1 ${} 和 #{} 的区别演示

    ① 根据 id 查找用户

    先看 #{} 操作根据 id 查找用户

    在这里插入图片描述在这里插入图片描述在这里插入图片描述

    执行的 JDBC 代码:(针对 int 类型的参数)
    在这里插入图片描述

    接下来${},其他代码不变
    在这里插入图片描述
    执行的 JDBC 代码:(针对 int 类型)
    在这里插入图片描述

    前者体现的预处理(预查询),后者体现的即时查询

    ② 根据用户名查找用户

    我们在看看针对 String 类型参数:
    先使用 #{} 根据用户名查找 用户
    在这里插入图片描述在这里插入图片描述在这里插入图片描述

    执行的 JDBC 代码:(针对 String 类型)

    在这里插入图片描述

    接下来${},其他代码不变

    在这里插入图片描述
    执行的 JDBC 代码:(针对 String 类型)
    在这里插入图片描述

    报错了,他的sql语句相当于是:
    在这里插入图片描述

    并没有加引号

    ③ 排序功能

    像一些商品基本都要有这个排序功能(按价格从高到低,从低到高)我这里就按 id 来排序

    先看 #{}
    在这里插入图片描述在这里插入图片描述
    报错了:
    在这里插入图片描述
    他的 sql 相当于:
    在这里插入图片描述

    再看 ${}
    在这里插入图片描述
    在这里插入图片描述

    当传递的是一个 SQL 关键字(SQL 命令)的时候,只能使用 ${},此时如果使用 #{} 就会认为传递的一个普通的值,而非 SQL 命令,所以执行就会报错
    注意 ${} 会有 SQL 注入问题,我们不得不使用 ${} 时,那么一定要在业务代码中,对传递的值进行安全验证

    ④ SQL 注入演示(${})

    假设我们有一个登录功能:
    先看 #{}
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    再看 ${}

    在这里插入图片描述
    在这里插入图片描述

    他的 SQL 是这样的(已经恒等了):

    在这里插入图片描述

    ⑤ 特殊查询: like 查询

    根据名称进行模糊查询
    先看 #{}
    在这里插入图片描述在这里插入图片描述

    在这里插入图片描述

    报错了:
    在这里插入图片描述

    他对应的 SQL:
    在这里插入图片描述

    这里他是不能直接使用 ${}.可以使用mysql内置函数 concat() 来处理:
    在这里插入图片描述在这里插入图片描述

    4.6.2 总结区别

    1. 定义不同: #{} 预处理,而 ${} 是直接替换
    2. 使用不同: #{} 适用于所有类型的参数匹配,但 ${} 只适用于数值类型
    3. 安全性不同: #{} 性能高,并且没有安全问题: 但 ${} 存在 SQL 注入的安全问题

    5. resultType VS resultMap

    在 resultType中,如果我们在实体类中的字段和mysql中的字段不匹配
    在这里插入图片描述
    这样我们是查不到 对应的值的,这时候我们就可以使用 resultMap 来手动进行映射的处理

     <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

    在这里插入图片描述

    6. 多表查询

    6.1 一对一查询

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

    我们在建一个文章实体类:
    在这里插入图片描述

    1. model层:

    import lombok.Data;
    
    @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
    • 13
    • 14

    多加了一个 UserInfo 类

    2. mapper层:

    import com.example.demo.model.ArticleInfo;
    import org.apache.ibatis.annotations.Mapper;
    import org.apache.ibatis.annotations.Param;
    
    @Mapper
    public interface ArticleMapper {
        //根据文章 id 获取文章
        public ArticleInfo getArticleById(@Param("id") Integer id);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3. 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

    4. 单元测试代码:
    在这里插入图片描述
    在这里插入图片描述

    @Slf4j 打印:
    在这里插入图片描述

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

    6.2 一对多实现

    跟一对一差不多,⼀对多需要使⽤ 标签,⽤法和 相同,

    1. model层:

    import lombok.Data;
    
    import java.util.List;
    
    /**
     * 用户实体类
     */
    @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
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    2. mapper层:

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

    3. XML层:

    <mapper namespace="com.example.demo.mapper.UserMapper">
        <resultMap id="BaseMap" type="com.example.demo.model.UserInfo">
            
            <id column="id" property="id">id>
            
            <result column="username" property="name">result>
            <result column="password" property="password">result>
            <result column="photo" property="photo">result>
            <result column="createtime" property="createtime">result>
            <result column="updatetime" property="updatetime">result>
            <result column="state" property="state">result>
            <collection property="artlist"
                        resultMap="com.example.demo.mapper.ArticleMapper.BaseMap"
                        columnPrefix="a_">
            collection>
        resultMap>
    
        <select id="getUserAndArticleByUid" 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
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    4. 单元测试代码:
    在这里插入图片描述在这里插入图片描述在这里插入图片描述

    7. 动态 SQL

    7.1 if 标签

    判断一个参数是否有值的,如果没值,那么就会隐藏 if 中 的 SQL
    就像我们在填写一些注册信息的时候,有些项可以填也可以不填,有些就是必须要填.

    简单语法:
    在这里插入图片描述

    举例:添加用户

    1. mapper层:

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

    2. XML:

     
        <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

    3. 不加 photo 的测试代码:
    在这里插入图片描述在这里插入图片描述

    4. 传值 photo 时:

    在这里插入图片描述在这里插入图片描述

    对应数据库值:
    在这里插入图片描述

    7.2 trim 标签

    最主要的作用就是 去除 SQL 语句前后多余的某个字符,向我们经常会在最后添加的值多加一个逗号啥的

    主要语法:
    在这里插入图片描述

    1. mapper层:

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

    2. XML层:

    <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

    3. 单元测试代码:
    在这里插入图片描述
    在这里插入图片描述

    7.3 where 标签

    主要作用就是实现查询中的 where sql 替换的,他可以实现如果没有任何的查询条件,那么他可以因此查询中的 where sql,但是如果存在查询条件,那么会生成 where 的 sql 查询,并且使用 where 标签可以自动的去除最前面一个 and 字符

    举例:根据 id 查找用户

    1. mapper层:

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

    注意:这里只返回一个,我就把数据库保留了一份
    在这里插入图片描述

    2. XML层:

    
        <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

    3. 单元测试代码:
    在这里插入图片描述
    在这里插入图片描述

    4. 加上 and:
    在这里插入图片描述

    测试代码:
    在这里插入图片描述
    在这里插入图片描述

    注意: and 在前面不能在后面
    在这里插入图片描述
    在这里插入图片描述

    7.4 set 标签

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

    举例,修改数据:在这里插入图片描述

    1. mapper层:

    int update2(UserInfo userInfo);
    
    • 1

    2. XML层:

    <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

    3. 测试代码:
    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    7.5 foreach 标签

    作用主要就是对集合进行循环的

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

    举例:根据多个用户 id 删除用户:

    1. mapper层:

    int delIds(List<Integer> ids);
    
    • 1

    2. XML层:

     <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

    方便观察,我们可以加几条数据:
    在这里插入图片描述
    3. 单元测试代码:
    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

  • 相关阅读:
    识别准确率达 95%,华能东方电厂财务机器人实践探索
    新版海螺影视主题模板M3.1全解密版本多功能苹果CMSv10后台自适应主题开源全解密版
    SSM - Springboot - MyBatis-Plus 全栈体系(二十五)
    随机手机号查询易语言代码
    【机器学习】线性分类【下】经典线性分类算法
    ESP32 (新建工程文件)-Vscode IDF新建工程(10)
    嵌入式鸿蒙系统开发语言与开发方法分析
    类与对象(三) 拷贝构造与赋值运算符重载
    ssl证书自动化快速部署和续费经验分享
    十七、完整神经网络模型训练步骤
  • 原文地址:https://blog.csdn.net/chenbaifan/article/details/125940174