


专栏:JavaEE 进阶跃迁营
个人主页:手握风云
目录
[二、MyBatis 入门](#二、MyBatis 入门)
[2.1. 创建项目](#2.1. 创建项目)
[2.2. 配置数据库连接字符串](#2.2. 配置数据库连接字符串)
[2.3. 数据准备](#2.3. 数据准备)
[2.3. 持久层代码](#2.3. 持久层代码)
[2.4. 单元测试](#2.4. 单元测试)
[三、MyBatis 的基础操作](#三、MyBatis 的基础操作)
[3.1. 打印日志](#3.1. 打印日志)
[3.2. 查(Select)](#3.2. 查(Select))
[3.3. 参数传递](#3.3. 参数传递)
一、MyBatis
MyBatis 是一款优秀的持久层(Persistence Layer)框架,其核心目标是简化 JDBC 的开发流程。根据官网定义,MyBatis 支持自定义 SQL、存储过程以及高级映射。在传统的 JDBC 开发中,程序员需要手动编写大量代码来管理数据库连接、设置参数以及处理结果集,过程繁琐且容易出错。MyBatis 通过封装这些底层细节,几乎免除了所有的 JDBC 代码,使开发者能够专注于 SQL 语句和业务逻辑本身。从架构上看,它通常位于 Web 应用程序的 Dao 层(数据访问层),负责程序与数据库之间的交互。
MyBatis 的前身是 Apache 的开源项目 iBatis。该项目于 2010 年由 Apache 迁移到了 Google Code,并正式更名为 MyBatis,随后在 2013 年迁移至 GitHub。这种历史背景使其拥有成熟的技术积淀和广泛的社区支持。作为一款半自动化的 ORM(对象关系映射)框架,MyBatis 既保留了 SQL 的灵活性,又提供了对象映射的便利性,非常适合需要对 SQL 进行精细控制的场景。
在技术实现上,MyBatis 提供了高度的灵活性,支持 XML 配置文件和 Java 注解两种方式来配置和映射原生信息。它能够将数据库中的记录映射为 Java 的原生类型、接口和 POJO(Plain Old Java Objects,普通老式 Java 对象)。通过简单的配置,MyBatis 就能自动将 SQL 查询结果转换为 Java 对象,彻底解决了传统 JDBC 中手动解析 ResultSet 的痛点。此外,它还支持动态 SQL 功能,允许根据不同的条件动态生成 SQL 语句,极大地提高了代码的可维护性和复用性。
二、MyBatis 入门
2.1. 创建项目

添加依赖 Spring Web,MySQL Driver,MyBatis FrameWork。创建好项目之后,会自动导入 MySQL 驱动和 MyBatis 依赖。
XML
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
2.2. 配置数据库连接字符串
XML
# 数据库连接配置
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
password 改成自己设置的数据库密码。如果密码为空,则使用"";如果密码为纯数字,也需要使用""。
2.3. 数据准备
sql
-- 1. 删除已存在的数据库(避免冲突)
DROP DATABASE IF EXISTS mybatis_test;
-- 2. 创建数据库并指定默认字符集
CREATE DATABASE mybatis_test DEFAULT CHARACTER SET utf8mb4;
-- 3. 使用目标数据库
USE mybatis_test;
-- 4. 删除已存在的用户表(避免冲突)
DROP TABLE IF EXISTS user_info;
-- 5. 创建用户表 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;
-- 6. 插入4条测试用户数据
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' );
java
package com.yang.test2_3_1.model;
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;
}
2.3. 持久层代码

java
package com.yang.test2_3_1.mapper;
import com.yang.test2_3_1.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper
public interface UserInfoMapper {
@Select("SELECT * FROM `user_info`")
public List<UserInfo> selectList();
}
java
package com.yang.test2_3_1.controller;
import com.yang.test2_3_1.model.UserInfo;
import com.yang.test2_3_1.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RequestMapping("/user")
@RestController
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/getList")
public List<UserInfo> getList() {
return userService.getList();
}
}
java
package com.yang.test2_3_1.service;
import com.yang.test2_3_1.mapper.UserInfoMapper;
import com.yang.test2_3_1.model.UserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserService {
@Autowired
private UserInfoMapper userInfoMapper;
public List<UserInfo> getList() {
return userInfoMapper.selectList();
}
}

2.4. 单元测试
上面的方法要是测试起来非常麻烦,而 test 包路径下已经包含了测试类。

java
package com.yang.test2_3_1;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class Test231ApplicationTests {
@Test
void contextLoads() {
}
}
@SpringBootTest 告诉 Spring Boot 去寻找主配置类(通常是带有 @SpringBootApplication 的类),并使用它来启动一个 Spring 应用上下文(Application Context)。@Test 注解用于标记方法为一个测试用例,运行测试时 JUnit 会执行这个方法。

如果我们写了多个接口,我们就可以使用 IDEA 创建测试类。我们使用快捷键 alt + 回车,点击 Test。


java
package com.yang.test2_3_1.mapper;
import com.yang.test2_3_1.model.UserInfo;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
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 UserInfoMapperTest {
@Autowired
private UserInfoMapper userInfoMapper;
@BeforeEach
void setUp() {
System.out.println("Before Each");
}
@AfterEach
void tearDown() {
System.out.println("After Each");
}
@Test
void selectList() {
List<UserInfo> userInfos = userInfoMapper.selectList();
System.out.println(userInfos);
}
}

三、MyBatis 的基础操作
3.1. 打印日志
java
mybatis:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
3.2. 查(Select)
java
@Select("SELECT id, username, `password`, age, gender, phone, " +
"delete_flag, create_time from user_info")
public List<UserInfo> selectList2();
java
@Test
void selectList2() {
List<UserInfo> userInfos = userInfoMapper.selectList2();
System.out.println(userInfos);
}

从上面的运行结果可以看出,delete_flag、create_time、update_time,这个字段名返回的是 null,这是因为在 Java 的命名规范中,字段名采用小驼峰命名,而 MySQL 中字段全部采用小写,如果字段对应不上,就会映射失败。

第一个方法:起别名。
java
@Select("SELECT id, username, `password`, age, gender, phone, " +
"delete_flag AS deleteFlag, create_time AS createTime," +
"update_time AS updateTime FROM `user_info`")
List<UserInfo> selectList3();
java
@Test
void selectList3() {
List<UserInfo> userInfos = userInfoMapper.selectList3();
System.out.println(userInfos);
}

第二个方法,结果映射。
java
@Results(id = "BaseMap", value = {
@Result(column = "delete_flag", property = "deleteFlag"),
@Result(column = "create_time", property = "createTime"),
@Result(column = "update_time", property = "updateTime"),
})
@Select("SELECT * FROM `user_info`")
List<UserInfo> selectList4();
java
@Test
void selectList4() {
List<UserInfo> userInfos = userInfoMapper.selectList4();
System.out.println(userInfos);
}
第三个方法,开启驼峰命名。先在 applicaiton 里面添加配置。
java
mybatis:
configuration:
map-underscore-to-camel-case: true #自动驼峰转换
java
@Select("SELECT id, username, `password`, age, gender, phone, " +
"delete_flag AS deleteFlag, create_time AS createTime," +
"update_time AS updateTime FROM `user_info`")
List<UserInfo> selectList5();
java
@Test
void selectList5() {
List<UserInfo> userInfos = userInfoMapper.selectList5();
System.out.println(userInfos);
}
3.3. 参数传递
参数传递的核心目的是解决 SQL 语句中参数固定化问题,实现动态传入参数,典型场景为根据动态条件(如 id)查询数据。
如果 Mapper 接口方法形参仅为**一个普通类型参数。**比如我们想查询 id = 4 的用户。
java
package com.yang.test2_3_1.mapper;
import com.yang.test2_3_1.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface UserInfoMapper2 {
@Select("SELECT * FROM `user_info` where id = #{id}")
UserInfo selectById(Integer id);
}
java
package com.yang.test2_3_1.mapper;
import com.yang.test2_3_1.model.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class UserInfoMapper2Test {
@Autowired
private UserInfoMapper2 userInfoMapper2;
@Test
void selectById() {
UserInfo userInfo1 = userInfoMapper2.selectById(1);
System.out.println(userInfo1);
}
}
能正确查询出 id=4 的用户数据,日志显示参数以预编译形式(? 占位)传入。
如果需明确参数标识(如多参数场景、参数名需与 SQL 中占位符严格对应),通过 @Param 为参数设置别名。
java
@Select("select username, `password`, age, gender, phone from user_info where id= #{userid} ")
UserInfo queryById(@Param("userid") Integer id); // 为id设置别名userid