MyBatis 到底怎么用?零基础也能上手的 Java 持久层入门指南
大家好,我是小陈,一名 211 高校的计算机专业研究生。平时喜欢写技术博客,尤其热衷于帮刚入行的同学少走弯路。今天这篇教程,就是源于我当初学 MyBatis 时踩过的坑——文档太官方、概念太抽象、代码示例又不完整。所以我想用最直白的语言、最贴近实战的方式,带你从零开始掌握 MyBatis。
你可能会问:为什么现在还要学 MyBatis? 毕竟 Spring Boot + JPA / Hibernate 听起来更“现代”。但现实是:国内绝大多数企业级 Java 项目(尤其是金融、政务系统)仍在广泛使用 MyBatis。它轻量、灵活、SQL 可控,非常适合对数据库操作有精细要求的场景。
顺便提一句,虽然本文聚焦 Java,但如果你也接触 Go(比如用 GORM),会发现 ORM 思想是相通的。而最近热门的 RAG(检索增强生成)系统中,后端往往也需要高效读写数据库——MyBatis 就是这类数据持久化的可靠选择之一。
一、MyBatis 是什么?能解决什么问题?
简单说:MyBatis 是一个 Java 的持久层框架。它的核心任务就一个:帮你把 Java 对象和数据库记录互相转换。
想象一下,没有框架时你要做什么:
- 手动加载 JDBC 驱动
- 写 Connection、Statement、ResultSet
- 处理 SQL 注入风险
- 手动把 ResultSet 一行行转成 Java 对象(俗称 “ORM”)
- 还要记得关资源、处理异常……
这些重复劳动不仅繁琐,还容易出错。MyBatis 把这些脏活累活封装好了,你只需要:
- 写 SQL(对,你没看错,MyBatis 不隐藏 SQL!)
- 定义 Java 类(POJO)
- 配置映射关系
剩下的,交给 MyBatis。
💡 我当初学的时候以为 ORM 框架都要像 Hibernate 那样“全自动”,结果发现 MyBatis 的“半自动”反而更适合业务复杂、SQL 需要调优的场景。
二、环境准备:5 分钟搭好开发环境
我们用最经典的组合:Java + Maven + MySQL + MyBatis
1. 前置条件
确保你已安装:
- JDK 8 或以上(推荐 JDK 17)
- Maven 3.6+
- MySQL 5.7+(或 MariaDB)
2. 创建 Maven 项目
在 IDE(如 IntelliJ IDEA)中新建一个 Maven 项目,pom.xml 添加以下依赖:
<dependencies>
<!-- MyBatis 核心 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.13</version>
</dependency>
<!-- MySQL 驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<!-- 单元测试(可选但推荐) -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
3. 初始化数据库
创建一个测试库 mybatis_demo,并建一张用户表:
CREATE DATABASE mybatis_demo;
USE mybatis_demo;
CREATE TABLE user (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
email VARCHAR(100)
);
插入几条测试数据:
INSERT INTO user (name, email) VALUES
('张三', 'zhangsan@example.com'),
('李四', 'lisi@example.com');
三、核心概念:3 个文件搞懂 MyBatis
MyBatis 的工作流程可以简化为:
Java 程序 → 调用 Mapper 接口 → MyBatis 执行对应 SQL → 返回 Java 对象
你需要理解以下三个关键部分:
1. 实体类(POJO)
代表数据库中的一行数据。例如 User.java:
public class User {
private Integer id;
private String name;
private String email;
// 必须有无参构造(MyBatis 反射需要)
public User() {}
// getter 和 setter(略,IDE 可自动生成)
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
}
2. Mapper 接口
定义你能对数据库执行哪些操作。例如 UserMapper.java:
public interface UserMapper {
List<User> findAll(); // 查询所有用户
User findById(Integer id); // 根据 ID 查询
void insert(User user); // 插入新用户
void update(User user); // 更新用户
void deleteById(Integer id); // 删除用户
}
⚠️ 注意:这是一个接口!不需要实现类。MyBatis 会在运行时动态生成实现。
3. SQL 映射文件(XML)
告诉 MyBatis 每个接口方法对应哪条 SQL。创建 UserMapper.xml(通常放在 resources/mapper/ 下):
<?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.mapper.UserMapper">
<select id="findAll" resultType="com.example.model.User">
SELECT * FROM user
</select>
<select id="findById" parameterType="int" resultType="com.example.model.User">
SELECT * FROM user WHERE id = #{id}
</select>
<insert id="insert" parameterType="com.example.model.User">
INSERT INTO user (name, email) VALUES (#{name}, #{email})
</insert>
<update id="update" parameterType="com.example.model.User">
UPDATE user SET name = #{name}, email = #{email} WHERE id = #{id}
</update>
<delete id="deleteById" parameterType="int">
DELETE FROM user WHERE id = #{id}
</delete>
</mapper>
关键点解释:
namespace必须是 Mapper 接口的全限定名id必须和接口方法名一致#{}是 MyBatis 的占位符,会自动防 SQL 注入
四、全局配置:让 MyBatis 知道去哪连数据库
创建 mybatis-config.xml(放在 resources 根目录):
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis_demo?useSSL=false&serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="your_password"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
</configuration>
🔒 安全提示:生产环境中密码不要硬编码!可用环境变量或配置中心。
五、实战:写一个完整的增删改查程序
现在,我们把前面所有东西串起来。
1. 工具类:获取 SqlSession
public class MyBatisUtil {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
throw new RuntimeException("初始化 MyBatis 失败", e);
}
}
public static SqlSession getSession() {
return sqlSessionFactory.openSession();
}
}
2. 测试主程序
public class Main {
public static void main(String[] args) {
try (SqlSession session = MyBatisUtil.getSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
// 1. 查询所有
System.out.println("=== 查询所有用户 ===");
List<User> users = mapper.findAll();
users.forEach(u -> System.out.println(u.getName() + " - " + u.getEmail()));
// 2. 新增用户
User newUser = new User();
newUser.setName("王五");
newUser.setEmail("wangwu@example.com");
mapper.insert(newUser);
session.commit(); // 注意:增删改需要手动提交!
// 3. 再次查询验证
System.out.println("\n=== 新增后再次查询 ===");
users = mapper.findAll();
users.forEach(u -> System.out.println(u.getId() + ": " + u.getName()));
}
}
}
运行结果类似:
=== 查询所有用户 ===
张三 - zhangsan@example.com
李四 - lisi@example.com
=== 新增后再次查询 ===
1: 张三
2: 李四
3: 王五
✅ 关键提醒:MyBatis 默认事务不自动提交!
insert/update/delete后必须调用session.commit(),否则数据不会写入数据库。
六、新手常见问题与避坑指南
❓ 问题 1:Mapper method was not found 错误
原因:XML 文件中的 namespace 或 id 和接口方法不匹配。
解决:检查三点:
- XML 的
namespace是否为接口全路径? - 方法名是否和
id一致? - XML 文件是否被正确加载?(检查
mybatis-config.xml中的<mappers>配置)
❓ 问题 2:中文乱码
原因:数据库连接未指定字符集。
解决:在 JDBC URL 中加上 &characterEncoding=utf8:
<property name="url" value="jdbc:mysql://...&characterEncoding=utf8"/>
❓ 问题 3:属性名和字段名不一致(如 userName vs user_name)
方案:使用 <resultMap> 显式映射:
<resultMap id="UserMap" type="User">
<id property="id" column="id"/>
<result property="userName" column="user_name"/>
<result property="email" column="email"/>
</resultMap>
<select id="findById" resultMap="UserMap">
SELECT id, user_name, email FROM user WHERE id = #{id}
</select>
❓ 问题 4:能否不用 XML,纯注解?
可以!MyBatis 支持注解方式(适合简单 SQL):
public interface UserMapper {
@Select("SELECT * FROM user")
List<User> findAll();
@Insert("INSERT INTO user(name, email) VALUES(#{name}, #{email})")
void insert(User user);
}
但复杂 SQL(如多表关联、动态 SQL)仍推荐 XML。
七、学习建议:下一步该学什么?
- 掌握动态 SQL:
<if>、<foreach>、<choose>等标签是 MyBatis 的精华。 - 集成 Spring Boot:实际项目几乎都用
mybatis-spring-boot-starter,省去手动管理 SqlSession。 - 了解缓存机制:MyBatis 有一级缓存(SqlSession 级)和二级缓存(Mapper 级)。
- 对比其他 ORM:试试 Hibernate(全自动)或 Go 的 GORM,理解不同设计哲学。
- 结合 RAG 场景思考:如果你在做基于向量数据库的检索增强生成系统,MyBatis 可用于管理元数据(如文档 ID、来源、更新时间等结构化信息)。
🌟 最后送大家一句话:不要怕写 SQL。MyBatis 的优势恰恰在于让你掌控 SQL,而不是被框架束缚。当你能写出高效的 SQL,再配合 MyBatis 的便利性,你就真正掌握了数据持久化的主动权。
希望这篇教程能帮你顺利入门 MyBatis。如果觉得有用,欢迎关注我的博客,后续我会更新《MyBatis 动态 SQL 实战》和《MyBatis + Spring Boot 最佳实践》系列!
作者:小陈 | 211 计算机研二在读 | 技术博客:xxx.com

评论 0