JavaEE【Spring】:MyBatis查询数据库

news2024/12/28 6:30:16

文章目录

  • 一、理论储备
    • 1、MyBatis 的概念
    • 2、MyBatis 的作用
  • 二、第⼀个MyBatis查询
    • 1、创建数据库和表
    • 2、添加MyBatis框架支持
      • ① 老项目添加MyBatis
        • Ⅰ. 新增功能
        • Ⅱ. EditStarters插件
      • ② 新项目添加MyBatis
    • 3、配置连接字符串和MyBatis
      • ① 配置连接字符串
      • ② 配置 MyBatis 中的 XML 路径
    • 4、添加业务代码
      • ① 添加实体类
      • ② 添加 mapper 接口
      • ③ 添加 UserMapper.xml
      • ④ 测试
        • Ⅰ. 使用接口测试
          • a. 添加 Service
          • b. 添加 Controller
          • c. 使用 postman 测试
        • Ⅱ. 使用单元测试
          • a. getAll 方法
          • b. getUserById 方法
  • 三、增、删、改操作
    • 1、准备工作
    • 2、增加用户操作
      • ① 不使用 @Param
      • ② 使用 @Param
      • ③ 返回自增 id
    • 3、删除用户操作
    • 4、修改用户操作
  • 四、查询操作
    • 1、单表查询
      • ① 参数占位符 #{} 和 ${}
        • Ⅰ. #{}
        • Ⅱ. ${}
        • Ⅲ. 对比
      • ② ${} 优点
      • ③ SQL 注入问题
        • Ⅰ. 概念
        • Ⅱ. ${} 带来的 SQL 注入问题
        • Ⅰ. #{}
        • Ⅱ. ${}
        • Ⅲ. 结论
      • ④ like 查询
    • 2、多表查询
      • ① 返回类型:resultType
      • ② 返回字典映射:resultMap
        • 字段名与属性名不同
      • ③ 多表查询
        • Ⅰ. 一对一的表映射
          • a. resultMap 映射
          • b. 查询时重命名
        • Ⅱ. 一对多:一个用户多篇文章案例
  • 五、复杂情况:动态SQL使用
    • 1、< if >标签
      • ① 使用方法
      • ② 案例
        • Ⅰ. 传值
        • Ⅱ. 不传值
    • 2、< trim >标签
      • ① 使用方法
      • ② 案例
    • 3、< where >标签
      • ① 使用方法
      • ② 案例
        • Ⅰ. 传值
        • Ⅱ. 不传值
    • 4、< set >标签
      • ① 使用方法
      • ② 案例
    • 5、< foreach >标签
      • ① 使用方法
      • ② 案例

一、理论储备

1、MyBatis 的概念

MyBatis 是比 JDBC 更简单的操作和读取数据库⼯具,它去除了繁琐的代码,通过简单的 XML 或 注解来配置和映射原始类型、接口和 Java POJO 为数据库记录。

2、MyBatis 的作用

对于后端开发来说,程序主要由两部分组成:后端程序 和 数据库。

我们依赖数据库连接工具,使得后端程序能够访问数据库,进行增删改查的操作。我们之前已经学习过一种工具(JDBC),但 JDBC 的操作太过繁琐了,MyBatis 更加简单。

回顾一下 JDBC 的流程:

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

二、第⼀个MyBatis查询

MyBatis 的组成:

  1. InterFace(接口):当前类的所有方法的声明
  2. XML:实现接口

MyBatis 也是⼀个 ORM 框架,ORM(Object Relational Mapping),即对象关系映射。在⾯向对象编程语⾔中,将关系型数据库中的数据与对象建⽴起映射关系,进⽽⾃动的完成数据与对象的互相转换:

  1. 将输⼊数据(即传⼊对象)+SQL 映射成原⽣ SQL
  2. 将结果集映射为返回对象,即输出对象

ORM 把数据库映射为对象:

  • 数据库表(table)–> 类(class)
  • 记录(record,⾏数据)–> 对象(object)
  • 字段(field) --> 对象的属性(attribute)

⼀般的 ORM 框架,会将数据库模型的每张表都映射为⼀个 Java 类。
也就是说使⽤ MyBatis 可以像操作对象⼀样来操作数据库中的表,可以实现对象和数据库表之间
的转换

1、创建数据库和表

接下来我们要实现的功能是:使⽤ MyBatis 的⽅式来读取⽤户表中的所有⽤户,SQL如下:

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

-- 添加一个用户信息
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);

2、添加MyBatis框架支持

添加 MyBatis 框架⽀持分为两种情况:

  • 对⾃⼰之前的 Spring 项⽬进⾏升级;
  • 创建⼀个全新的 MyBatis 和 Spring Boot 的项⽬。

① 老项目添加MyBatis

Ⅰ. 新增功能

在 pom.xml 文件中,直接增加框架支持:

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>

Ⅱ. EditStarters插件

在 pom.xml 文件中,鼠标右键 -> Generate -> EditStarters:增加 如下两个框架即可
在这里插入图片描述

② 新项目添加MyBatis

在创建时,直接添加框架即可:
在这里插入图片描述

3、配置连接字符串和MyBatis

① 配置连接字符串

在 application.yml 中添加如下内容:

# 数据库连接配置
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mycnblog?characterEncoding=utf8&useSSL=false
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver

注意:

如果使⽤ mysql-connector-java 是 5.x 之前的使⽤的是“com.mysql.jdbc.Driver”,
如果是⼤于 5.x 使⽤的是“com.mysql.cj.jdbc.Driver”。

② 配置 MyBatis 中的 XML 路径

MyBatis 的 XML 中保存是查询数据库的具体操作 SQL,配置如下:

# 配置 mybatis xml 的⽂件路径,在 resources/mapper 创建所有表的 xml ⽂件
mybatis:
  mapper-locations: classpath:mapper/**Mapper.xml
  configuration: # 配置打印 mybatis 执行的 SQL
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

在这里插入图片描述

4、添加业务代码

① 添加实体类

创建一个与表对应的实体类:
在这里插入图片描述
代码如下:

package com.example.mybatisdemo.model;

import lombok.Data;

import java.util.Date;

/**
 * 用户信息
 * 普通的实体类,用于 MyBatis 做数据库表(userinfo)的映射
 * 注意事项:标准类属性名称和 userinfo 表的字段完全一致()。
 */
@Data
public class UserInfo {
    /**
     * 用户id
     */
    private Integer id;
    /**
     * 用户名
     */
    private String username;
    /**
     * 密码
     */
    private String password;
    /**
     * 电话号码
     */
    private String photo;
    /**
     * 创建时间
     */
    private Date createTime;
    /**
     * 修改时间
     */
    private Date updateTime;
    /**
     * 状态
     */
    private Integer state;
}

② 添加 mapper 接口

创建一个与表对应的 mapper 接口:
在这里插入图片描述
代码如下:

package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * 使用 @Mapper,让接口变为 mybatis 的接口,不可忽略
 */
@Mapper
public interface UserInfoMapper {
    /**
     * 查询所有的信息
     * @return
     */
    public List<UserInfo> getAll();

    /**
     * 传参查询
     * @param id
     * @return
     */
    public UserInfo getUserById(@Param("id")Integer id);
}

③ 添加 UserMapper.xml

在 resources 目录下的 mapper 包下创建 xml 文件:
在这里插入图片描述
代码如下:

<?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.example.mybatisdemo.mapper.UserInfoMapper">
    <select id="getAll" resultType="com.example.mybatisdemo.model.UserInfo">
        select * from userinfo
    </select>

    <select id="getUserById" resultType="com.example.mybatisdemo.model.UserInfo">
        select * from userinfo where id=#{id}
    </select>
</mapper>

说明

  • < mapper>标签:
    • namespace -> 实现的接口名(包名+类名)
  • < select>标签:
    • id -> 实现的方法名
    • resultType -> 返回的数据类型(对应的实体类名)
    • 在传参查询的时候,通过 #{id} 的方式来获取参数(此处的 id 与接口中的 @Param 注解所传 id 相同)

④ 测试

Ⅰ. 使用接口测试

a. 添加 Service
package com.example.mybatisdemo.service;

import com.example.mybatisdemo.mapper.UserInfoMapper;
import com.example.mybatisdemo.model.UserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserInfoService {
    @Autowired
    private UserInfoMapper userInfoMapper;

    /**
     * 查询所有的信息
     * @return
     */
    public List<UserInfo> getAll(){
        return userInfoMapper.getAll();
    }

    /**
     * 传参查询
     * @param id
     * @return
     */
    public UserInfo getUserById(Integer id){
        return userInfoMapper.getUserById(id);
    }
}
b. 添加 Controller
package com.example.mybatisdemo.controller;

import com.example.mybatisdemo.model.UserInfo;
import com.example.mybatisdemo.service.UserInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;

@RestController
@RequestMapping("/userinfo")
public class UserInfoController {

    @Autowired
    private UserInfoService userInfoService;

    /**
     * 查询所有的信息
     * @return
     */
    @RequestMapping("/getAll")
    public List<UserInfo> getAll() {
        return userInfoService.getAll();
    }

    /**
     * 传参查询
     * @param id
     * @return
     */
    @RequestMapping("/getUserById")
    public UserInfo getUserById(@RequestParam(value = "id", required = false) Integer id) {
        return userInfoService.getUserById(id);
    }
}
c. 使用 postman 测试

测试:http://localhost:8080/userinfo/getall
在这里插入图片描述
测试:http://localhost:8080/userinfo/getuserbyid?id=1
在这里插入图片描述

Ⅱ. 使用单元测试

在 Spring Boot 中,使用单元测试,教程链接:单元测试

测试类代码:

package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest // 当前测试的上下文环境为 Spring Boot
class UserInfoMapperTest {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Test
    void getAll() {
        List<UserInfo> list = userInfoMapper.getAll();
        for (UserInfo user : list) {
            System.out.println(user.toString());
        }
    }

    @Test
    void getUserById() {
        UserInfo userInfo = userInfoMapper.getUserById(1);
        System.out.println(userInfo);
    }
}
a. getAll 方法

在这里插入图片描述

b. getUserById 方法

在这里插入图片描述

三、增、删、改操作

1、准备工作

创建表:

-- 使用数据数据
use mycnblog;

-- 创建文章表
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';

创建实体类:

package com.example.mybatisdemo.model;

import lombok.Data;

import java.util.Date;

/**
 * 文章的实体类
 */
@Data
public class ArticleInfo {
    /**
     * 文章id
     */
    private Integer id;
    /**
     * 标题
      */
    private String title;
    /**
     * 正文
     */
    private String content;
    /**
     * 创建时间
     */
    private Date createTime;
    /**
     * 修改时间
     */
    private Date updateTime;
    /**
     * 发布文章的uid
     */
    private Integer uid;
    /**
     * 访问量
     */
    private Integer rcount;
    /**
     * 状态
     */
    private Integer state;
}

2、增加用户操作

① 不使用 @Param

mapper 接口:

package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.ArticleInfo;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface ArticleInfoMapper {
    /**
     * 添加方法
     * @return
     */
    public Integer add(ArticleInfo articleInfo);
}

Mapper.xml:

<?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.example.mybatisdemo.mapper.ArticleInfoMapper">
    <insert id="add">
        insert into articleinfo(title, content, uid)
        values (#{title}, #{content}, #{uid})
    </insert>
</mapper>

单元测试代码为:

package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.ArticleInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
class ArticleInfoMapperTest {

    @Autowired
    private ArticleInfoMapper articleInfoMapper;

    @Test
    void add() {
        ArticleInfo articleInfo = new ArticleInfo();
        articleInfo.setTitle("MyBatis");
        articleInfo.setContent("hello,MyBatis!");
        articleInfo.setUid(1);
        Integer result = articleInfoMapper.add(articleInfo);
        System.out.println("添加结果为:" + result);
    }
}

单元测试结果为:
在这里插入图片描述

② 使用 @Param

mapper 接口:

package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.ArticleInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

@Mapper
public interface ArticleInfoMapper {
    /**
     * 添加方法
     * @param articleInfo
     * @return
     */
    public Integer add(@Param("articleInfo") ArticleInfo articleInfo);
}

Mapper.xml:

<?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.example.mybatisdemo.mapper.ArticleInfoMapper">
    <insert id="add">
        insert into articleinfo(title, content, uid)
        values (#{articleInfo.title}, #{articleInfo.content}, #{articleInfo.uid})
    </insert>
</mapper>

单元测试代码为:

package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.ArticleInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
class ArticleInfoMapperTest {

    @Autowired
    private ArticleInfoMapper articleInfoMapper;

    @Test
    void add() {
        ArticleInfo articleInfo = new ArticleInfo();
        articleInfo.setTitle("MyBatis");
        articleInfo.setContent("hello,MyBatis!");
        articleInfo.setUid(1);
        Integer result = articleInfoMapper.add(articleInfo);
        System.out.println("添加结果为:" + result);
    }
}

单元测试结果为:
在这里插入图片描述

③ 返回自增 id

返回自增 id 可以通过 mapper.xml中的 < insert> 标签 的属性来设置:

  • useGeneratedKeys:取出由数据库内部⽣成的主键,默认值:false。
  • keyColumn:设置⽣成键值在表中的列名,当主键列不是表中的第⼀列的时候,是必须设置的。如果⽣成列不⽌⼀个,可以⽤逗号分隔多个属性名称。
  • keyProperty:指定能够唯⼀识别对象的属性,如果⽣成列不⽌⼀个,可以⽤逗号分隔多个属性名称。

mapper 接口:

package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.ArticleInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

@Mapper
public interface ArticleInfoMapper {
    /**
     * 添加方法(得到自增主键的id)
     * @param articleInfo
     * @return
     */
    public Integer addGetId(@Param("articleInfo") ArticleInfo articleInfo);
}

Mapper.xml:

<?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.example.mybatisdemo.mapper.ArticleInfoMapper">
    <insert id="addGetId" useGeneratedKeys="true" keyProperty="id">
        insert into articleinfo(title, content, uid)
        values (#{articleInfo.title}, #{articleInfo.content}, #{articleInfo.uid})
    </insert>
</mapper>

单元测试代码为:

package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.ArticleInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
class ArticleInfoMapperTest {

    @Autowired
    private ArticleInfoMapper articleInfoMapper;

    @Test
    void addGetId() {
        ArticleInfo articleInfo = new ArticleInfo();
        articleInfo.setTitle("MyBatis自增主键id");
        articleInfo.setContent("MyBatis主键id在自增!");
        articleInfo.setUid(1);
        Integer result = articleInfoMapper.addGetId(articleInfo);
        System.out.println("添加结果为:" + result +
                " | 自增id:" + articleInfo.getId());
    }
}

单元测试结果为:
在这里插入图片描述

3、删除用户操作

mapper 接口:

package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.ArticleInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

@Mapper
public interface ArticleInfoMapper {
    /**
     * 删除单条数据
     * @param id
     * @return
     */
    public int delById(@Param("id") Integer id);
}

Mapper.xml:

<?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.example.mybatisdemo.mapper.ArticleInfoMapper">
    <delete id="delById">
        delete from articleinfo where id=#{id}
    </delete>
</mapper>

单元测试代码为:

package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.ArticleInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
class ArticleInfoMapperTest {

    @Autowired
    private ArticleInfoMapper articleInfoMapper;

    @Test
    void delById() {
        Integer result = articleInfoMapper.delById(5);
        System.out.println("删除结果为:" + result);
    }
}

单元测试结果为:
在这里插入图片描述

4、修改用户操作

mapper 接口:

package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.ArticleInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

@Mapper
public interface ArticleInfoMapper {
	/**
     * 修改标题
     *
     * @param id
     * @param title
     * @return
     */
    public Integer updateTitle(@Param("id") Integer id, @Param("title") String title);
}

Mapper.xml:

<?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.example.mybatisdemo.mapper.ArticleInfoMapper">
    <update id="updateTitle">
        update articleinfo set title=#{title} where id=#{id}
    </update>
</mapper>

单元测试代码为:

package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.ArticleInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
class ArticleInfoMapperTest {

    @Autowired
    private ArticleInfoMapper articleInfoMapper;

    @Test
    void updateTitle() {
        Integer result = articleInfoMapper.updateTitle(1, "hello");
        System.out.println("修改结果为:" + result);
    }
}

单元测试结果为:
在这里插入图片描述

四、查询操作

1、单表查询

① 参数占位符 #{} 和 ${}

案例:
mapper接口:

package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * 使用 @Mapper,让接口变为 mybatis 的接口,不可忽略
 */
@Mapper
public interface UserInfoMapper {
    /**
     * 根据用户名查询
     * @param username
     * @return
     */
    public UserInfo getUserByName(@Param("username")String username);
}

单元测试类:

package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest // 当前测试的上下文环境为 Spring Boot
class UserInfoMapperTest {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Test
    void getUserByName() {
        UserInfo userInfo = userInfoMapper.getUserByName("admin");
        System.out.println("userInfo -> "+userInfo);
    }
}

Ⅰ. #{}

Mapper.xml:

<?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.example.mybatisdemo.mapper.UserInfoMapper">
    <select id="getUserByName" resultType="com.example.mybatisdemo.model.UserInfo">
        select * from userinfo where username=#{username}
    </select>
</mapper>

单元测试结果为:
在这里插入图片描述

Ⅱ. ${}

Mapper.xml:

<?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.example.mybatisdemo.mapper.UserInfoMapper">
    <select id="getUserByName" resultType="com.example.mybatisdemo.model.UserInfo">
        select * from userinfo where username=${username}
    </select>
</mapper>

单元测试结果为:
在这里插入图片描述

Ⅲ. 对比

  • #{}:预编译处理。
  • ${}:字符直接替换。

MyBatis 在处理 #{} 时,会将 SQL 中的 #{} 替换为?号,使⽤ PreparedStatement 的 set ⽅法来赋值。MyBatis 在处理 ${} 时,会把 ${} 替换成变量的值。

在刚刚的案例中,我们使用分别使用了 #{} 和 ${}:

  • #{}:select * from userinfo where username=‘admin’
  • ${}:select * from userinfo where username=admin

所以在使用 ${} 的时候就会报错,因为没有一个字段名叫 admin,改正 -> 加上单引号:

Mapper.xml:

<?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.example.mybatisdemo.mapper.UserInfoMapper">
    <select id="getUserByName" resultType="com.example.mybatisdemo.model.UserInfo">
        select * from userinfo where username='${username}'
    </select>
</mapper>

单元测试结果为:
在这里插入图片描述

但这种使用方法其实是不严谨的,对于字符串我们可以加上单引号,那其他类型的数据查询呢?我们再加上单引号,就会存在数据类型转换,当数据库较大时,花费的时间就非常多了,所以这样做也是有风险的!

② ${} 优点

刚刚我们对比了 #{} 和 ${},我们发现使用 ${} 对于字符串来说要加引号,很麻烦,对于其他数据类型又不合理,那 ${} 有什么用呢?
实际上 ${} 可以专递 SQL 关键字

案例:
mapper接口:

package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * 使用 @Mapper,让接口变为 mybatis 的接口,不可忽略
 */
@Mapper
public interface UserInfoMapper {
    /**
     * 查询所有的信息(根据排序条件进行排序)
     * @param order
     * @return
     */
    public List<UserInfo> getAllByOrder(@Param("order")String order);
}

Mapper.xml:

<?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.example.mybatisdemo.mapper.UserInfoMapper">
	<select id="getAllByOrder" resultType="com.example.mybatisdemo.model.UserInfo">
        select * from userinfo order by id ${order}
    </select>
</mapper>

单元测试代码:

package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest // 当前测试的上下文环境为 Spring Boot
class UserInfoMapperTest {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Test
    void getAllByOrder() {
        List<UserInfo> list = userInfoMapper.getAllByOrder("desc");
        for (UserInfo user : list) {
            System.out.println(user.toString());
        }
    }
}

单元测试结果为:
在这里插入图片描述
这里如果使用 #{} 查询时,如果传递的值为 String,它就会加上单引号,从而导致 SQL 错误。

③ SQL 注入问题

Ⅰ. 概念

在正常情况下,我们进行登录时,要同时匹配用户名和密码,当有一项错误时,就无法查询到数据:
在这里插入图片描述
但是当我们不知道密码时,我们可以采用漏洞来获取数据:
在这里插入图片描述
我们通过 1=‘1’ 这个恒成立的条件来获取密码,无论用户名和密码是什么,因为 1=‘1’ ,所以一定能查询到所有用户名对应的密码,这就是 SQL 注入!

Ⅱ. ${} 带来的 SQL 注入问题

mapper接口:

package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * 使用 @Mapper,让接口变为 mybatis 的接口,不可忽略
 */
@Mapper
public interface UserInfoMapper {
    /**
     * 用户登录
     * @param username
     * @param password
     * @return
     */
    public UserInfo login(@Param("username")String username,
                          @Param("password")String password);
}

单元测试代码:

package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest // 当前测试的上下文环境为 Spring Boot
class UserInfoMapperTest {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Test
    void login() {
        String username = "abc";
        String password = "' or 1='1";
        UserInfo userInfo = userInfoMapper.login(username,password);
        System.out.println("userInfo -> "+userInfo);
    }
}

Ⅰ. #{}

Mapper.xml:

<?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.example.mybatisdemo.mapper.UserInfoMapper">
    <select id="login" resultType="com.example.mybatisdemo.model.UserInfo">
        select * from userinfo where username=#{username} and password=#{password}
    </select>
</mapper>

单元测试结果为:
在这里插入图片描述
我们可以发现,使用 #{} 时,当用户名和密码不对时,无法查询到数据。

Ⅱ. ${}

Mapper.xml:

<?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.example.mybatisdemo.mapper.UserInfoMapper">
    <select id="login" resultType="com.example.mybatisdemo.model.UserInfo">
        select * from userinfo where username='${username}' and password='${password}'
    </select>
</mapper>

单元测试结果为:
在这里插入图片描述
我们可以发现,使用 ${} 时,即使用户名和密码完全不对,但是通过 SQL 注入,我们仍然能够查询出结果。

Ⅲ. 结论

用于查询的字段,尽量使用 #{} 预查询的⽅式。

④ like 查询

我们在使用 like 进行模糊查询的时候,查询的输入项可能在前面也可能在后边,所以我们要在前后都加上 %,使用 #{} 时:

<select id="findUserByName" resultType="com.example.mybatisdemo.model.UserInfo">
	select * from userinfo where username like '%#{username}%';
</select>

这样是会报错的,原因:
上面的 sql -> select * from userinfo where username like ‘%‘username’%’;

这里又不能使用 ${},存在安全隐患,我们又没法用穷举的方式验证 ${} 是否安全,那应该怎么办呢?
实际上,我们可以使用 mysql 的内置函数 concat() 来拼接 %,代码如下:

<select id="findUserByName" resultType="com.example.mybatisdemo.model.UserInfo">
	select * from userinfo where username like concat('%',#{username},'%');
</select>

这样我们就可以实现模糊查询了。

2、多表查询

① 返回类型:resultType

  • 如果是增、删、改返回搜影响的⾏数,那么在 mapper.xml 中是可以不设置返回的类型的;
  • 但对于查询来说,即使是最简单查询⽤户的名称也要设置返回的类型。

在使用查询的时候,我们就需要声明其返回类型,使用 resultType 进行返回,直接定义到实体类即可。

<?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.example.mybatisdemo.mapper.UserInfoMapper">
    <select id="getAll" resultType="com.example.mybatisdemo.model.UserInfo">
        select * from userinfo
    </select>
</mapper>

② 返回字典映射:resultMap

resultMap 使⽤场景:

  • 字段名称和程序中的属性名不同的情况,可使⽤ resultMap 配置映射;
  • ⼀对⼀和⼀对多关系可以使⽤ resultMap 映射并查询数据。

字段名与属性名不同

如图,在定义实体类时,我们将 username 定义为 name,那么通过查询,就不能正确赋值。
在这里插入图片描述
查询结果如下:
在这里插入图片描述
这时候就需要用到 resultMap:
在这里插入图片描述
Mapper.xml:

<?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.example.mybatisdemo.mapper.UserInfoMapper">
    <resultMap id="BashMap" type="com.example.mybatisdemo.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>
    </resultMap>

    <select id="getAll" resultMap="BashMap">
        select * from userinfo
    </select>
</mapper>

单元测试结果如下:
在这里插入图片描述

③ 多表查询

Ⅰ. 一对一的表映射

案例:查询文章的所有信息已经文章的作者。

a. resultMap 映射

ArticleInfo 类(文章实体类):加入需要查询的字段

package com.example.mybatisdemo.model;

import lombok.Data;

import java.util.Date;

/**
 * 文章的实体类
 */
@Data
public class ArticleInfo {
    /**
     * 文章id
     */
    private Integer id;
    /**
     * 标题
      */
    private String title;
    /**
     * 正文
     */
    private String content;
    /**
     * 创建时间
     */
    private Date createTime;
    /**
     * 修改时间
     */
    private Date updateTime;
    /**
     * 发布文章的uid
     */
    private Integer uid;
    /**
     * 访问量
     */
    private Integer rcount;
    /**
     * 状态
     */
    private Integer state;
    /**
     * 文章作者名
     */
    private String name;
}

mapper接口:

package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.ArticleInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

@Mapper
public interface ArticleInfoMapper {

   /**
     * 查询所有的信息
     * @return
     */
    public List<ArticleInfo> getAll();
}

Mapper.xml:

<?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.example.mybatisdemo.mapper.ArticleInfoMapper">
	<resultMap id="BaseMap" type="com.example.mybatisdemo.model.ArticleInfo">
        <id property="id" column="id"></id>
        <result property="title" column="title"></result>
        <result property="content" column="content"></result>
        <result property="createTime" column="createTime"></result>
        <result property="updateTime" column="updateTime"></result>
        <result property="uid" column="uid"></result>
        <result property="rcount" column="rcount"></result>
        <result property="state" column="state"></result>
        <result property="username" column="name"></result>
    </resultMap>
    
    <select id="getAll" resultMap="BaseMap">
        select a.*,u.username from articleinfo a
        left join userinfo u
        on a.uid=u.id
    </select>
</mapper>

单元测试代码:

package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.ArticleInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
class ArticleInfoMapperTest {

    @Autowired
    private ArticleInfoMapper articleInfoMapper;

    @Test
    void getAll() {
        List<ArticleInfo> list = articleInfoMapper.getAll();
        for (ArticleInfo item : list) {
            System.out.println(item);
        }
    }
}

单元测试结果:
在这里插入图片描述

b. 查询时重命名

Mapper.xml:

<?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.example.mybatisdemo.mapper.ArticleInfoMapper">
    <select id="getAll" resultType="com.example.mybatisdemo.model.ArticleInfo">
        select a.*,u.username as name from articleinfo a
        left join userinfo u
        on a.uid=u.id
    </select>
</mapper>

单元测试结果:
在这里插入图片描述

Ⅱ. 一对多:一个用户多篇文章案例

案例:查询用户的所有文章

UserInfo 类(文章实体类):加入需要查询的字段

package com.example.mybatisdemo.model;

import lombok.Data;

import java.util.Date;

/**
 * 用户信息
 * 普通的实体类,用于 MyBatis 做数据库表(userinfo)的映射
 * 注意事项:标准类属性名称和 userinfo 表的字段完全一致()。
 */
@Data
public class UserInfo {
    /**
     * 用户id
     */
    private Integer id;
    /**
     * 用户名
     */
    private String username;
    /**
     * 密码
     */
    private String password;
    /**
     * 电话号码
     */
    private String photo;
    /**
     * 创建时间
     */
    private Date createTime;
    /**
     * 修改时间
     */
    private Date updateTime;
    /**
     * 状态
     */
    private Integer state;
    /**
     * 文章
     */
    private String title;
}

mapper接口:

package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * 使用 @Mapper,让接口变为 mybatis 的接口,不可忽略
 */
@Mapper
public interface UserInfoMapper {
    /**
     * 查询用户的所有文章
     * @param id
     * @return
     */
    public List<UserInfo> getArticleListByUid(@Param("id")Integer id);
}

Mapper.xml:

<?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.example.mybatisdemo.mapper.UserInfoMapper">
    <select id="getArticleListByUid" resultType="com.example.mybatisdemo.model.UserInfo">
        select u.*,a.title as title from userinfo u
        left join articleinfo a
        on u.id=a.uid where u.id=#{id}
    </select>
</mapper>

Service 类:

package com.example.mybatisdemo.service;

import com.example.mybatisdemo.mapper.UserInfoMapper;
import com.example.mybatisdemo.model.ArticleInfo;
import com.example.mybatisdemo.model.UserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserInfoService {
    @Autowired
    private UserInfoMapper userInfoMapper;

    /**
     * 查询用户的所有文章
     * @param uid
     * @return
     */
    public List<UserInfo> getArticleListByUid(Integer uid){
        return userInfoMapper.getArticleListByUid(uid);
    }
}

Controller 类:

package com.example.mybatisdemo.controller;

import com.example.mybatisdemo.model.ArticleInfo;
import com.example.mybatisdemo.model.UserInfo;
import com.example.mybatisdemo.service.UserInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/userinfo")
public class UserInfoController {

    @Autowired
    private UserInfoService userInfoService;

    /**
     * 查询用户的所有文章
     * @param uid
     * @return
     */
    @RequestMapping("/getArticleListByUid")
    public List<UserInfo> getArticleListByUid(@RequestParam("uid")Integer uid){
        return userInfoService.getArticleListByUid(uid);
    }
}

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

五、复杂情况:动态SQL使用

官⽅⽂档:mybatis - 动态 SQL

1、< if >标签

在用户注册时,时长会有一些必传参数,那么我们在注册时,不确定是否传参的时候,该怎么办呢?

① 使用方法

<if test="...... != null">
    ......
</if>

② 案例

mapper接口:

package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * 使用 @Mapper,让接口变为 mybatis 的接口,不可忽略
 */
@Mapper
public interface UserInfoMapper {
    /**
     * 增加用户
     * @param username
     * @param password
     * @param photo
     * @return
     */
    public Integer add(@Param("username")String username,
                       @Param("password")String password,
                       @Param("photo")String photo);
}

Mapper.xml:

<?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.example.mybatisdemo.mapper.UserInfoMapper">
    <insert id="add">
        insert into userinfo(username,
        password,
        <if test="photo!=null">
            photo
        </if>
        )
        values (#{username},
        #{password},
        <if test="photo!=null">
            #{photo}
        </if>)
    </insert>
</mapper>

Ⅰ. 传值

单元测试类:

package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest // 当前测试的上下文环境为 Spring Boot
class UserInfoMapperTest {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Test
    void add() {
        Integer result = userInfoMapper.add("张三", "zhangsan", "111111");
        System.out.println("添加用户结果: " + result);
    }
}

单元测试结果:
在这里插入图片描述

Ⅱ. 不传值

单元测试类:

package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest // 当前测试的上下文环境为 Spring Boot
class UserInfoMapperTest {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Test
    void add() {
        Integer result = userInfoMapper.add("张三", "zhangsan", null);
        System.out.println("添加用户结果: " + result);
    }
}

单元测试结果:
在这里插入图片描述
这里就会报错,这是因为我们将可选参数作为最后传参导致逗号无法确定,从而导致语法错误。

2、< trim >标签

对于上述案例,我们使用 trim 标签就可以解决:

① 使用方法

< trim>标签中有如下属性:

  • prefix:表示整个语句块,以prefix的值作为前缀
  • suffix:表示整个语句块,以suffix的值作为后缀
  • prefixOverrides:表示整个语句块要去除掉的前缀
  • suffixOverrides:表示整个语句块要去除掉的后缀
<trim prefix="" suffix="" prefixOverrides="" suffixOverrides="">
   .......
</trim>

② 案例

Mapper.xml:

<?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.example.mybatisdemo.mapper.UserInfoMapper">
    <insert id="add">
        insert into userinfo
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="username!=null">
                username,
            </if>
            <if test="password!=null">
                password,
            </if>
            <if test="photo!=null">
                photo,
            </if>
        </trim>
        values
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="username!=null">
                #{username},
            </if>
            <if test="password!=null">
                #{password},
            </if>
            <if test="photo!=null">
                #{photo},
            </if>
        </trim>
    </insert>
</mapper>

单元测试类:

package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest // 当前测试的上下文环境为 Spring Boot
class UserInfoMapperTest {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Test
    void add() {
        Integer result = userInfoMapper.add("张三", "zhangsan", null);
        System.out.println("添加用户结果: " + result);
    }
}

单元测试结果:
在这里插入图片描述

3、< where >标签

① 使用方法

<where>
	.......
</where>

<!-- where可以用trim 替换 -->
<trim prefix="where" prefixOverrides="and">

② 案例

mapper接口:

package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * 使用 @Mapper,让接口变为 mybatis 的接口,不可忽略
 */
@Mapper
public interface UserInfoMapper {
    /**
     * 根据用户名查询
     * @param username
     * @return
     */
    public UserInfo getUserByName(@Param("username")String username);
}

Mapper.xml:

<?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.example.mybatisdemo.mapper.UserInfoMapper">
    <select id="getUserByName" resultType="com.example.mybatisdemo.model.UserInfo">
        select * from userinfo
        <where>
            <if test="username!=null">
                and username = #{username}
            </if>
        </where>
    </select>
</mapper>

Ⅰ. 传值

单元测试类:

package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest // 当前测试的上下文环境为 Spring Boot
class UserInfoMapperTest {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Test
    void getUserByName() {
        UserInfo userInfo = userInfoMapper.getUserByName("admin");
        System.out.println("userInfo -> " + userInfo);
    }
}

单元测试结果:
在这里插入图片描述

Ⅱ. 不传值

单元测试类:

package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest // 当前测试的上下文环境为 Spring Boot
class UserInfoMapperTest {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Test
    void getUserByName() {
        UserInfo userInfo = userInfoMapper.getUserByName(null);
        System.out.println("userInfo -> " + userInfo);
    }
}

单元测试结果:
在这里插入图片描述

4、< set >标签

① 使用方法

<set>
	.......
</set>

<!-- set可以用trim 替换 -->
<trim prefix="set" suffixOverrides=",">

② 案例

mapper接口:

package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.ArticleInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

@Mapper
public interface ArticleInfoMapper {
	/**
     * 修改标题
     *
     * @param id
     * @param title
     * @return
     */
    public Integer updateTitle(@Param("id") Integer id, @Param("title") String title);
}

Mapper.xml:

<?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.example.mybatisdemo.mapper.ArticleInfoMapper">
    <update id="updateTitle">
        update articleinfo
        <set>
            <if test="title!=null">
                title=#{title}
            </if>
        </set>
        where id = #{id}
    </update>
</mapper>

单元测试类:

package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.ArticleInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
class ArticleInfoMapperTest {

    @Autowired
    private ArticleInfoMapper articleInfoMapper;

    @Test
    void updateTitle() {
        Integer result = articleInfoMapper.updateTitle(1, "hello");
        System.out.println("修改结果为:" + result);
    }
}

单元测试结果为:
在这里插入图片描述

5、< foreach >标签

① 使用方法

< foreach>标签有如下属性:

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

② 案例

mapper接口:

package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * 使用 @Mapper,让接口变为 mybatis 的接口,不可忽略
 */
@Mapper
public interface UserInfoMapper {
    /**
     * 多条用户的删除
     * @param ids
     * @return
     */
    public Integer delByIds(List<Integer> ids);
}

Mapper.xml:

<?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.example.mybatisdemo.mapper.UserInfoMapper">
    <delete id="delByIds">
        delete from userinfo where id in
        <foreach collection="ids" item="id" open="(" close=")" separator=",">
            #{id}
        </foreach>
    </delete>
</mapper>

单元测试类:

package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.ArrayList;
import java.util.List;

@SpringBootTest // 当前测试的上下文环境为 Spring Boot
class UserInfoMapperTest {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Test
    void delByIds() {
        List<Integer> list = new ArrayList<>();
        list.add(7);
        list.add(8);
        list.add(9);
        Integer result = userInfoMapper.delByIds(list);
        System.out.println("删除了: " + result);
    }
}

单元测试结果为:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/137311.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据标注平台如何保护用户数据安全?

近期&#xff0c;在《麻省理工科技评论》在一篇万字长文调查中&#xff0c;一位年轻女子坐在自家的马桶上的图片也被扫地机器人拍摄下来&#xff0c;并被流传到网上、大范围传播。但事实上&#xff0c;这也并非是一件新鲜事了。例如&#xff0c;2020年秋&#xff0c;一系列从低…

为什么MySQL 要选择 B+树

一、什么是索引 在关系数据库中&#xff0c;索引是一种单独的、物理的对数据库表中一列或多列的值进行排序的一种存储结构。再直白点就是我们可以把索引理解成图书或者字典的目录。 既然索引是数据的一种存储结构&#xff0c;那么我们必然要对其进行存储&#xff0c;同时&…

你可以不用Git,但不能不会Git(二)基础(上)

目录 一.环境配置 二.本地初始化仓库 三.文件的两种状态 四.文件加入暂存区 五.文件提交与删除 1.提交文件 2.删除文件 一.环境配置 当安装Git后首先要做的事情是设置用户名称和email地址。这是非 常重要的&#xff0c;因为每次Git提交都会使用该用户信息。 设置用户信…

#G. 红旗招展

Description小J占山为王有一段时间了&#xff0c;他决定把自己的地盘打扮一下---将各种颜色的旗插在山头上当然某一座的山头只能用一种颜色的旗。整个地盘有N个山头&#xff0c;可看成是一棵有N个节点的树。小J还是有一点艺术细胞的&#xff0c;他不想整个地盘杂乱无章。于是他…

Kubernetes安装ingress-controller

IngressController 1. 安装 1.1 查看ingress-nginx的版本匹配 https://github.com/kubernetes/ingress-nginx/blob/main/README.md#readme 下载配置 wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.1.2/deploy/static/provider/cloud/de…

【回答问题】ChatGPT上线了!给我推荐20个比较流行的图像实例分割模型

给我推荐20个比较流行的图像实例分割模型 U-Net Mask R-CNN FCN SegNet PSPNet DeepLabv3 DenseASPP LinkNet RefineNet ENet ICNet BiSeNet CRF-RNN GCN Tiramisu FRRN DeepLabv3 PANet MaskLab Hybrid Task Cascade给我推荐20个比较流行的图像实例分割模型源码 好的&#x…

java学习之类变量

目录 一、类变量的引出 需解决的问题 传统代码 代码问题 解决方法 运行结果 二、类变量的内存布局 特点 内存中的位置 三、类变量定义 四、类变量语法 五、访问类变量 六、类变量细节 第一条 第二条 第三条 第四条 第五条 第六条 第七条 一、类变量的引出 需…

PHP8---MySQL扩展

目录 一、MySQL扩展的介绍 二、PHP和MySQL连接的基本操作 &#xff08;1&#xff09;MySQL连接的准备工作 &#xff08;2&#xff09;插入删除操作 三、查询操作 &#xff08;1&#xff09;mysqli_fetch_assoc &#xff08;2&#xff09;mysqli_fetch_row &#xff08;3…

19. 网站响应数据加一个简单的密,就能挡住80%的爬虫,你信吗?

本篇博客我们实现响应加密&#xff0c;由于本案例是JS逆向阶段的第一个案例&#xff0c;所以采用最基础加密手段。 爬虫训练场源码同步仓库为 GitCode 项目采集测试地址&#xff1a;爬虫训练场 爬虫训练场框架搭建Python Flask 端 Base64加密前台解密字符串渲染数据框架搭建 本…

Es之mapping

1&#xff09;、字段类型 2&#xff09;、映射 Mapping&#xff08;映射&#xff09; Mapping 是用来定义一个文档&#xff08;document&#xff09;&#xff0c;以及它所包含的属性&#xff08;field&#xff09;是如何存储和 索引的。比如&#xff0c;使用 mapping 来定义…

深入解析Linux虚拟化KVM-Qemu分析之KVM源码

说明&#xff1a; KVM版本&#xff1a;5.9.1QEMU版本&#xff1a;5.0.0工具&#xff1a;Source Insight 3.5&#xff0c; Visio 1. 概述 从本文开始将开始source code的系列分析了&#xff1b;KVM作为内核模块&#xff0c;可以认为是一个中间层&#xff0c;向上对接用户的控制…

idea中热部署插件JRebel的激活方式

idea中热部署插件JRebel的激活方式 一、打开jrebel 激活面板&#xff0c;如图&#xff1a; 二、选中Team URL&#xff08;connect to online licensing service&#xff09; 1、在上面的框中输入激活的url地址 http://127.0.0.1:8888/132d042c-3b1a-4c45-9044-b7897c3de7882…

遗传算法改进(IGA)+python代码实现

遗传算法改进&#xff08;IGA&#xff09;python代码实现一、变异概率的改进&#xff08;1&#xff09;单点变异&#xff08;2&#xff09;多点变异&#xff08;3&#xff09;选择性的突变概率二、交叉概率的改进三、适应度函数的改进&#xff08;1&#xff09;sigmoid函数&…

PGL 系列(六)node2vec

node2vec DeepWalk存在的问题是比较简单直接,而图结构往往是一个复杂结构,需要考虑很多因素,在深度优先搜索方法之外,还有广度优先搜索,结合以上两种方式可以更好的探索图模型,即node2vec。

华为交换机配置

文章目录网络规划与设计机房连线图PON网络配置网络规划与设计 OLT: 网络光线路终端(Optical Line Terminal) ONU分为两种 MDU&#xff08;Multi-DwellingUnit&#xff0c;多住户单元&#xff09; MDU主要应用于FTTB应用类型下的多个住宅用户的接入&#xff0c;一般具有至少4个…

【JDK工具】jinfo、jps、jstack、jstat、jmap

目录一、前言二、关键工具2.1 jps 显示所有JAVA进程信息1. 参数信息2. 常用命令2.2 jinfo 查看虚拟机配置参数信息1. 查看虚拟机参数 jinfo -flags pid2. 查看虚拟机指定参数 jinfo -flag 具体参数 pid3. 查看环境变量 jinfo -sysprops pid4. 参数列表2.3 jstack1. 能排查哪些问…

springboot整合之Validated参数校验

特别说明&#xff1a;本次项目整合基于idea进行的&#xff0c;如果使用Eclipse可能操作会略有不同&#xff0c;不过总的来说不影响。 springboot整合之如何选择版本及项目搭建 springboot整合之版本号统一管理 springboot整合mybatis-plusdurid数据库连接池 springboot整…

JVM面试大总结

一、汇总 JVM是运行在操作系统之上的&#xff0c;它与硬件没有直接的交互。先说一下JVM的内存区域&#xff0c;当函数开始运行时&#xff0c;JVM拿到自己的内存将自己的内存区域进行了分割&#xff0c;分为五块区域&#xff1a;线程共享的有堆、方法区&#xff0c;线程私有的有…

Hadoop MapReduce 介绍

Hadoop MapReduceMapReduce核心思想设计构思什么是MapReduceMapReduce的特点MapReduce的不足&#xff08;局限性&#xff09;MapReduce组成Hadoop MapReduce实现流程map阶段执行过程Reduce阶段执行过程Shuffle机制Map端ShuffleReducer端的shuffleMapReduce核心思想 MapReduce的…

基于MVC的在线购物系统

摘 要本毕业设计的内容是设计并且实现一个基于net语言的在线购物系统。它是在Windows下&#xff0c;以SQL Server为数据库开发平台&#xff0c;Tomcat网络信息服务作为应用服务器。在线购物系统的功能已基本实现&#xff0c;主要包括首页、个人中心、会员用户管理、商品分类管理…