Java EE 进阶:8.MyBatis 操作数据库(入门)(第一弹)

目录

前言

[JDBC 操作示例回顾](#JDBC 操作示例回顾)

[1.什么是 MyBatis?](#1.什么是 MyBatis?)

[2.MyBatis 入门](#2.MyBatis 入门)

[2.1 准备工作](#2.1 准备工作)

[2.1.1 创建工程](#2.1.1 创建工程)

[2.1.2 数据准备](#2.1.2 数据准备)

[2.2 配置数据库连接字符串](#2.2 配置数据库连接字符串)

[2.3 写持久层代码](#2.3 写持久层代码)

[2.4 单元测试](#2.4 单元测试)

[使用 Idea 自动生成测试类](#使用 Idea 自动生成测试类)

接口测试

创建测试用例(对上面的补充)

​编辑


本节目标

  1. 使用MyBatis完成简单的增删改查操作, 参数传递.

  2. 掌握MyBatis的两种写法: 注解 和 XML方式

  3. 掌握MyBatis 相关的日志配置

前言

在应用分层学习时, 我们了解到web应用程序一般分为三层,即:Controller、Service、Dao .

之前的案例中,请求流程如下: 浏览器发起请求, 先请求Controller, Controller接收到请求之后, 调用 Service进行业务逻辑处理, Service再调用Dao, 但是Dao层的数据是Mock的, 真实的数据应该从数据库中读取.

我们学习MySQL数据库时,已经学习了JDBC来操作数据库, 但是JDBC操作太复杂了.

JDBC 操作示例回顾

我们先来回顾一下 JDBC 的操作流程:

  1. 创建数据库连接池 DataSource

这一步都是一样的

  1. 通过 DataSource 获取数据库连接 Connection

  2. 编写要执行带 ? 占位符的 SQL 语句

  3. 通过 Connection 及 SQL 创建操作命令对象 Statement

  4. 替换占位符:指定要替换的数据库字段类型,占位符索引及要替换的值

  5. 使用 Statement 执行 SQL 语句

  6. 查询操作:返回结果集 ResultSet,更新操作:返回更新的数量

  7. 处理结果集

  8. 释放资源

下面的一个完整案例,展示了通过 JDBC 的 API 向数据库中添加一条记录,修改一条记录,查询一条记录的操作。

java 复制代码
-- 创建数据库
create database if not exists library default character set utf8mb4;
-- 使用数据库
use library;
-- 创建表
create table if not exists soft_bookrack (
  book_name varchar(32) NOT NULL,
  book_author varchar(32) NOT NULL,
  book_isbn varchar(32) NOT NULL primary key
);

以下是 JDBC 操作的具体实现代码:

java 复制代码
package com.example.demo.mapper;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class SimpleJdbcOperation {

    private final DataSource dataSource;

    public SimpleJdbcOperation(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    /**
     * 添加一本书
     */
    public void addBook() {
        Connection connection = null;
        PreparedStatement stmt = null;
        try {
            //获取数据库连接
            connection = dataSource.getConnection();
            //创建语句
            stmt = connection.prepareStatement(
                    "insert into soft_bookrack (book_name, book_author, book_isbn) values (?,?,?);"
            );
            //参数绑定
            stmt.setString(1, "Spring in Action");
            stmt.setString(2, "Craig Walls");
            stmt.setString(3, "9787115417305");
            //执行语句
            stmt.execute();
        } catch (SQLException e) {
            //处理异常信息
        } finally {
            //清理资源
            try {
                if (stmt != null) {
                    stmt.close();
                }
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                //
            }
        }
    }

    /**
     * 更新一本书
     */
    public void updateBook() {
        Connection connection = null;
        PreparedStatement stmt = null;
        try {
            //获取数据库连接
            connection = dataSource.getConnection();
            //创建语句
            stmt = connection.prepareStatement(
                    "update soft_bookrack set book_author=? where book_isbn=?;"
            );
            //参数绑定
            stmt.setString(1, "张卫滨");
            stmt.setString(2, "9787115417305");
            //执行语句
            stmt.execute();
        } catch (SQLException e) {
            //处理异常信息
        } finally {
            //清理资源
            try {
                if (stmt != null) {
                    stmt.close();
                }
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                //
            }
        }
    }

    /**
     * 查询一本书
     */
    public void queryBook() {
        Connection connection = null;
        PreparedStatement stmt = null;
        ResultSet rs = null;
        Book book = null;
        try {
            //获取数据库连接
            connection = dataSource.getConnection();
            //创建语句
            stmt = connection.prepareStatement(
                    "select book_name, book_author, book_isbn from soft_bookrack where book_isbn =?"
            );
            //参数绑定
            stmt.setString(1, "9787115417305");
            //执行语句
            rs = stmt.executeQuery();
            if (rs.next()) {
                book = new Book();
                book.setName(rs.getString("book_name"));
                book.setAuthor(rs.getString("book_author"));
                book.setIsbn(rs.getString("book_isbn"));
            }
            System.out.println(book);
        } catch (SQLException e) {
            //处理异常信息
        } finally {
            //清理资源
            try {
                if (rs != null) {
                    rs.close();
                }
                if (stmt != null) {
                    stmt.close();
                }
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                //
            }
        }
    }

    public static class Book {
        private String name;
        private String author;
        private String isbn;
        //省略 setter getter 方法
    }
}

分析上述 CURD 操作,可以看出很多相同点👇

  1. 创建数据库连接池 DataSource

这一步都是一样的

  1. 通过 DataSource 获取数据库连接 Connection

这一步都是一样的

  1. 编写要执行带 ? 占位符的 SQL 语句

这个与业务有关

  1. 通过 Connection 及 SQL 创建操作命令对象 Statement

这一步都是一样的

  1. 替换占位符:指定要替换的数据库字段类型,占位符索引及要替换的值

这个与 SQL 有关,也就是第三步

  1. 使用 Statement 执行 SQL 语句

这一步都是一样的

  1. 查询操作:返回结果集 ResultSet,更新操作:返回更新的数量

就是字段和 Java 属性的映射

  1. 处理结果集

这一步都是一样的

  1. 释放资源

这一步都是一样的

所以一整个流程下来,需要我们自己写的代码也就是一个 SQL 语句和参数,多说就是再加上一个处理查询结果集

框架就可以帮我们把共同的东西封装起来,个性化的东西我们采用配置或者给我们提供入口即可~~

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

答案是肯定的,这就是我们要学习 MyBatis 的真正原因,它可以帮助我们更方便、更快速的操作数据库,MyBatis 可以说就是把能封装的都封装起来了~~

1.什么是 MyBatis?

闲聊:大白话就是访问数据库的,JDBC 写起来太麻烦了,我们对 JDBC 进行封装,然后封装出来一个 MyBatis,直接替代 JDBC 了,因为要想存起来不丢就得存到外存,也就是数据库,这也就持久了~~

• MyBatis是一款优秀的 持久层 框架,用于简化 JDBC 的开发。

闲聊:MyBatis 和 Spring 没有关系~~

我们知道 Spring 非常开放,如果你做的框架比较好,Spring Boot 就会给它集成进来,所以 Spring Boot 把 MyBatis 集成进来了,我们依旧是通过 Spring Boot 来去学习 MyBatis

Spring Boot 集成了 MyBatis,就像 Spring Boot 集成了 Tomcat 一样,但是它们还是两家人,只不过我们觉得这东西很好,就像我们的 12306 集成了外卖,集成了保险一样,我觉得这个保险做的挺好,就把它集成到我的框架里面了,但是外卖、保险和 12306 不是一家人~~

答疑:Servlet 集成了吗?

我们的 Spring 是基于 Servlet 进行封装的,它本身就是站在巨人的肩膀上,站在 Servlet 的基础上封装成的 Spring

• MyBatis本是 Apache的一个开源项目 iBatis,2010年这个项目由 apache 迁移到了 google code,并且改名为 MyBatis 。2013年11月迁移到 Github.

• 官网:MyBatis中文网

在上面我们提到一个词:持久层

• 持久层:指的就是持久化操作的层, 通常指数据访问层(dao), 是用来操作数据库的.

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

接下来,我们就通过一个入门程序,让大家感受一下通过 Mybatis 如何来操作数据库

2.MyBatis 入门

Mybatis操作数据库的步骤:

  1. 准备工作(创建 springboot 工程、数据库表准备、实体类)

  2. 引入 Mybatis 的相关依赖,配置 Mybatis (数据库连接信息)

  3. 编写SQL语句(注解/XML)

  4. 测试

2.1 准备工作

2.1.1 创建工程

创建springboot工程,并导入 mybatis 的起步依赖、mysql的驱动包

Mybatis 是一个持久层框架, 具体的数据存储和数据操作还是在 MySQL 中操作的, 所以需要添加 MySQL 驱动

然后我们还是把没用的东西删掉👇

还是只保留这两个即可👇

当然,要是社区版的话需要在 pom.xml 文件中删掉一些没用的东西,删成这样👇

项目工程创建完成后,自动在 pom.xml 文件中,导入 Mybatis 依赖和 MySQL 驱动依赖

版本会随着 SpringBoot 版本发生变化

SpringBoot 3.X对用 MyBatis 版本为 3.X

对应关系参考:Introduction -- mybatis-spring-boot-autoconfigure

XML 复制代码
<!--Mybatis 依赖包-->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>3.0.3</version>
</dependency>
<!--mysql驱动包-->
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>

这个依赖加上了 spring-boot,所以这个依赖只能在 SpringBoot 下使用的,而下面这个依赖是在所有的 Java 框架中都可以使用的👇

XML 复制代码
<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>x.x.x</version>
</dependency>

之前我们学习 JDBC 的时候的调用关系:JDBC→MySQL驱动→MySQL

现在我们学习 MyBatis 的调用关系:MyBatis→MySQL驱动→MySQL

所以我们需要添加 MySQL 驱动,当然,如果你数据库是别的,那就添加别的驱动

如果你是老项目的话,可以使用我们之前安装的插件,进行添加👇

2.1.2 数据准备

创建用户表,并创建对应的实体类 User

sql 复制代码
-- 创建数据库
DROP DATABASE IF EXISTS mybatis_test;
CREATE DATABASE mybatis_test DEFAULT CHARACTER SET utf8mb4;


-- 使用数据数据
USE mybatis_test;

-- 创建表[用户表]
DROP TABLE IF EXISTS user_info;
CREATE TABLE `user_info` (
    `id` INT ( 11 ) NOT NULL AUTO_INCREMENT,
    `username` VARCHAR ( 127 ) NOT NULL,
    `password` VARCHAR ( 127 ) NOT NULL,
    `age` TINYINT ( 4 ) NOT NULL,
    `gender` TINYINT ( 4 ) DEFAULT '0' COMMENT '1-男 2-女 0-默认',
    `phone` VARCHAR ( 15 ) DEFAULT NULL,
    `delete_flag` TINYINT ( 4 ) DEFAULT 0 COMMENT '0-正常, 1-删除',
    `create_time` DATETIME DEFAULT now(),
    `update_time` DATETIME DEFAULT now() ON UPDATE now(),
    PRIMARY KEY ( `id` )
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4;

-- 添加用户信息
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'admin', 'admin', 18, 1, '18612340001' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'zhangsan', 'zhangsan', 18, 1, '18612340002' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'lisi', 'lisi', 18, 1, '18612340003' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'wangwu', 'wangwu', 18, 1, '18612340004' );

将上述内容复制,然后点击新建查询,粘贴到可视化工具上运行👇

此时这个表就建立好了,还有着一些初始化的数据👇

然后注意上述 SQL 中在更新位置用到了 ON UPDATE now(),这一句指的就是在我更新数据的时候,我可以不用去设置它的值,它会自动更新,可以理解为一个触发器吧,当我触发更新这个操作的时候,它会给它自动设置,比如现在的时间是👇

接下来把值改为 1 ,再点击下面的 √ 保存,我们会发现时间自动更新了👇

这个也是我们在创建表的时候经常去用的

创建对应的实体类 UserInfo

实体类的属性名与表中的字段名一一对应

java 复制代码
import lombok.Data;
import java.util.Date;

@Data
public class UserInfo {
    private Integer id;
    private String username;
    private String password;
    private Integer age;
    private Integer gender;
    private String phone;
    private Integer deleteFlag;
    private Date createTime;
    private Date updateTime;
}

闲聊:规范~~

数据库字段:全部小写,单词之间使用 下划线( _ )分割

Java 规范:属性使用小驼峰来表示

通常把数据库字段和 Java 属性一一对应起来~~

2.2 配置数据库连接字符串

Mybatis中要连接数据库,需要数据库相关参数配置

• MySQL驱动类

• 登录名

• 密码

• 数据库连接字符串

如果是application.yml文件, 配置内容如下:

java 复制代码
# 数据库连接配置
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver

注意事项:

如果使用 MySQL 是 5.x 之前的使用的是"com.mysql.jdbc.Driver",如果是大于 5.x 使用的

是"com.mysql.cj.jdbc.Driver".

如果是application.properties文件, 配置内容如下:

java 复制代码
#驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#数据库连接的url
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false
#连接数据库的用户名
spring.datasource.username=root
#连接数据库的密码
spring.datasource.password=root

闲聊:这些东西不需要背,以后工作中用的时候可以直接从博客这里来拿,或者你自己存到码云里,工作不考你背代码,考的是你解决问题的能力,在这里你只需要复制下来就可以了~~

MySQL 驱动新版本默认不允许公钥获取,所以当出现报错的时候用下面的配置,表示允许👇(用户名和密码要和本地的对应上~~)

复制代码
spring:
  application:
    name: mybatis-demo

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

2.3 写持久层代码

在项目中, 创建持久层接口UserInfoMapper

我们来实现这样的 SQL 语句👇

java 复制代码
package com.bit.mybatis.mapper;

import com.bit.mybatis.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: CoderYanger
 * Date: 2026-11-04
 * Time: 21:26
 */
@Mapper//交给Spring管理,否则执行不了,这也就是文件夹和接口名都带Mapper的原因
public interface UserInfoMapper {
    @Select("select * from user_info")
    List<UserInfo> selectAll();
}

从此处也能看到 MyBatis 的前身:ibatis👇

Mybatis 的持久层接口规范一般都叫 XxxMapper

@Mapper注解:表示是MyBatis中的Mapper接口

• 程序运行时, 框架会自动生成接口的实现类对象(代理对象),并给交Spring的IOC容器管理

• @Select注解:代表的就是select查询,也就是注解对应方法的具体实现内容.

2.4 单元测试

在创建出来的 SpringBoot 工程中,在 src 下的 test 目录下,已经自动帮我们创建好了测试类 ,我们可以直接使用这个测试类来进行测试.

接口的实现有两种方式

1.注解的方式

2.XML的方式(后面讲)

下面演示的是注解的方式👇

java 复制代码
import com.example.demo.mapper.UserInfoMapper;
import com.example.demo.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
class DemoApplicationTests {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Test
    void contextLoads() {
        List<UserInfo> userInfoList = userInfoMapper.queryAllUser();
        System.out.println(userInfoList);
    }
}

测试类上添加了注解 @SpringBootTest,该测试类在运行时,就会自动加载Spring的运行环境.

我们通过@Autowired这个注解, 注入我们要测试的类, 就可以开始进行测试了

运行结果如下:

返回结果中, 可以看到, 只有SQL语句中查询的列对应的属性才有赋值

使用 Idea 自动生成测试类

除此之外, 也可以使用Idea自动生成测试类

  1. 在需要测试的Mapper接口中, 右键 -> Generate -> Test
  1. 选择要测试的方法, 点击 OK

此时就在这里生成测试代码了👇

  1. 书写测试代码
java 复制代码
package com.bit.mybatis.mapper;

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.*;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: CoderYanger
 * Date: 2026-11-04
 * Time: 21:40
 */
@SpringBootTest//加上这个就可以运行测试了
class UserInfoMapperTest {
    //将刚刚交给Spring管理的UserInfoMapper注入进来
    @Autowired
    private UserInfoMapper userInfoMapper;
    
    @Test
    void selectAll() {
        System.out.println(userInfoMapper.selectAll());
    }
}

记得加 @SpringBootTest 注解, 加载Spring运行环境

运行结果:

接口测试

除了上面的测试方法,还可以用接口来进行测试👇Controller 调用 Service,Service 调用 Mapper,Mapper 从数据库中获取数据,然后返回,返回给 Service,Service 再返回给 Controller,Controller 再把数据统一返回~~

Controller👇

java 复制代码
@RequestMapping("/user")
@RestController
public class UserInfoController {
    //注入进来
    @Autowired
    private UserService userService;
    @RequestMapping("/getAllUser")
    public List<UserInfo> getAllUser(){
        return userService.getAllUser();
    }
}

Service👇

java 复制代码
@Service
public class UserService {
    @Autowired//注入进来
    private UserInfoMapper userInfoMapper;
    public List<UserInfo> getAllUser() {
        return userInfoMapper.selectAll();
    }
}

启动服务后测试👇此时我们就把数据库中的值打印出来了👇

每一个都这么写确实麻烦,所以上述讲了单元测试~~


测试对我们还是比较重要的,像之前我们写测试的时候都是直接在 main 方法里写测试(像前面 IoC 那样去写)👇

java 复制代码
package com.bit.mybatis;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

@SpringBootApplication
public class MybatisDemoApplication {

    public static void main(String[] args) {
        ApplicationContext context=SpringApplication.run(MybatisDemoApplication.class, args);
    }

}

这其实是不规范的,因为我们的测试代码是不写在 main 里面的,我们拿的时候直接注入就可以了👇

java 复制代码
package com.bit.mybatis;

import com.bit.mybatis.mapper.UserInfoMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;

@SpringBootTest
class MybatisDemoApplicationTests {
    @Autowired
    private ApplicationContext context;
    @Test
    void contextLoads() {
        //在这里就可以直接用了
        UserInfoMapper bean=context.getBean(UserInfoMapper.class);
        bean.selectAll().stream().forEach(x->System.out.println(x));
    }
}

运行之后也是可以正常获取的👇

因为我们已经提前交给 Spring 管理了👇

当然,规范归规范,有些人比较懒,也就在 main 直接写然后测试了,所以只能说不规范,但是大家也有这么用的~~

答疑:

Q1:接口不能实例化,那么这里将接口交给 Spring 管理,Spring 管理的是啥呀??

接口是要实例化的~~,我们下面这一行就已经给它实例化了👇

之前学习 Java 的时候可能还需要去创建一个 class 去实现 UserInfo👇

java 复制代码
@Component
public class UserInfoMapperImpl implements UserInfoMapper{
    @Override
    public List<UserInfo> selectAll() {
        return null;
    }
}

确实,在十多年前,ibatis 确实是这么用的,我们实现确实不在里面,而是在外面再创建一个类,但是现在不是了,现在在接口上直接就给它实现了,就不用再写这个实现类了~~

注意:前面学的五大注解是 Spring 的,现在学的 @Mapper 是 MyBatis 的,这两者之间没有关系,不要弄混了~~

Q2:为啥加上 @Mapper 也是交给 Spring 进行管理了??

因为我们的依赖是二者结合的依赖👇(MyBatis 告诉 Spring 让它管理起来)

Q3:什么是 Stream 流??

这是 Java8 新增的一种处理集合数据的方式,下面这行代码👇

java 复制代码
bean.selectAll().stream().forEach(x->System.out.println(x));

等价于👇

java 复制代码
        List<UserInfo> userInfos=bean.selectAll();
        for(UserInfo userInfo:userInfos){
            System.out.println(userInfo);
        }

相当于我们把 这个 List 转换成了一个 流,然后对这个流进行处理,.stream() 就是把它变成 流 了,我们知道 流 肯定要一滴一滴下来,我们就是对每一滴水进行处理,也就是 userInfo 了,处理的内容就是 x->System.out.println(x),这个 x 就是 流 里(userInfo)的元素,然后去打印

当然,除了打印,还可以用 filter 进行过滤操作,比如下面代码就是把 List 里面的 gender=1 的数据过滤出来,然后收集成一个 List👇

java 复制代码
userInfos.stream().filter(x->x.getGender()==1).collect(Collectors.toList());

要是想了解更多,可以自行去网上搜索了解~~


@SpringBootTest 表示:加载 Spring 的运行环境

当你需要使用 Spring 的运行环境,比如注入某个 bean,需要加 @SpringBootTest,不需要则不加

@Test 表示:这是一个测试方法,我们就可以直接运行了,也可以同时创建多个,都可以运行👇,不然还得去写 main 方法,很麻烦~~

在测试方法前面的箭头表示只执行当前测试方法,最上面类上的箭头表示执行所有测试方法👇


创建测试用例(对上面的补充)

上述测试用例并不是我们手写的,而是生成的~~

点击确定👇

java 复制代码
@SpringBootTest//加上这个就可以运行测试了
class UserInfoMapperTest {
    //将刚刚交给Spring管理的UserInfoMapper注入进来
    @Autowired
    private UserInfoMapper userInfoMapper;

    @Test
    void selectAll() {
        System.out.println(userInfoMapper.selectAll());
    }

    @BeforeEach//在每一个测试方法之前执行
    void setUp() {
        System.out.println("before...");
    }

    @AfterEach//在每一个测试方法之后执行
    void tearDown() {
        System.out.println("after...");
    }
}

运行时我们就能发现,是先打印 before,再打印 after,中间是程序运行的内容👇

这两个是每个测试方法都会执行一次,而不是执行一次就完事儿了,下面我们用两个测试方法来体会一下👇

java 复制代码
@SpringBootTest//加上这个就可以运行测试了
class UserInfoMapperTest {
    //将刚刚交给Spring管理的UserInfoMapper注入进来
    @Autowired
    private UserInfoMapper userInfoMapper;

    @Test
    void selectAll() {
        System.out.println(userInfoMapper.selectAll());
    }
    @Test
    void selectAll2() {
        System.out.println(userInfoMapper.selectAll());
    }

    @BeforeEach//在每一个测试方法之前执行
    void setUp() {
        System.out.println("before...");
    }

    @AfterEach//在每一个测试方法之后执行
    void tearDown() {
        System.out.println("after...");
    }
}

我们发现都执行了👇

相关推荐
程序员沉梦听雨16 分钟前
【搜索引擎】Kibana使用指南
java·后端·学习笔记
XLYcmy1 小时前
信息检索报告数字经济赋能城市低碳治理的路径研究——基于“传统数据库 + 生成式人工智能”双轮驱动的检索实践 检索实施与结果分析 Web of Science
数据库·ai·llm·prompt·ssci·deepseek·wos
Decay__1 小时前
21_MySQL 优化案例集 —— 慢 SQL 优化、索引重构与参数调整收益对比
运维·数据库·sql·mysql·架构
奶油话梅糖2 小时前
打开项目 0.9 秒、内存只有 IDEA 的 1/12:OpenIDEA 用 Rust 把 IntelliJ IDEA 重造了一遍
java·rust·github·intellij-idea
vipxieliang2 小时前
语言对比卡:PHP vs Go vs Java 的优缺点、适用场景与「为什么选 PHP」
java·go·php
Rain的Java大神之路2 小时前
公交App上“还有2站,约5分钟”怎么实现?90%的人答错这道大厂面试题:GPS漂移、ETA不准、10万QPS热点读全拆透(附完整代码)
java·后端·面试
codigger2 小时前
MySQL 深分页优化:limit 100000, 10 慢在哪,怎么救
数据库·sql·mysql·程序员
golang学习记2 小时前
IDEA 2026.3 远程开发迎来重磅升级
java·ide·intellij-idea·远程开发
麦壳饼2 小时前
SonnetDB 5.0 正式发布:增强 SQL 与事务,开放九模型 MCP 读写
数据库·人工智能·sql·sonnetdb