MyBatis基础教程:Java持久层框架入门
大家好,我是小林,一个刚从成都某大专毕业的前端自学选手。没错,你没看错——我主攻前端,但最近被公司“安排”去搞后端,理由是“全栈工程师更吃香”。虽然内心一万只草泥马奔腾而过,但为了月底那点工资(和不被裁的KPI),还是硬着头皮啃起了 Java 后端技术栈。
上周五晚上,产品又提了个“小需求”:要加个用户行为日志统计模块,得存到 MySQL 里。我一脸懵:前端发个请求完事了?结果后端老哥甩给我一句:“你不是会写代码吗?用 MyBatis 接一下。” 好家伙,我连 pom.xml 是啥都快忘了,还得现学 MyBatis。
于是就有了这篇新手友好型 MyBatis 入门教程。不吹牛,纯实战踩坑总结,适合像我这种半路出家、Vim 党、讨厌 IDE 自动补全的“野生程序员”。
为啥选 MyBatis?而不是 JPA 或者手写 JDBC?
先说背景。我们公司是个中小型 SaaS 产品团队,后端主要用 Spring Boot + MyBatis 的组合。为啥不用 Spring Data JPA?产品经理说:“我们要灵活查数据,有些 SQL 得手写优化。” 运维大哥也补刀:“JPA 那个 N+1 查询问题,线上炸过一次,别碰。”
MyBatis 的核心思想就俩字:SQL 和对象解耦。它不像 JPA 那样全自动映射,而是让你手写 SQL,然后通过 XML 或注解把结果映射成 Java 对象。对前端转后端的我来说,反而更容易理解——毕竟 SQL 我还能看懂,ORM 黑盒直接劝退。
而且,MyBatis 在国内企业级应用里真·主流。你看那些大厂招聘 JD,十个有八个写着“熟悉 MyBatis”,比 Redis 还常见(手动狗头)。
上手第一步:项目搭建(别被 Maven 劝退)
我用的是 Spring Boot 2.7 + MyBatis 3.5 + MySQL 8。Maven 配置如下(别问为啥不用 Gradle,我们组统一 Maven,说是为了“兼容老项目”):
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
application.yml 里配数据库:
spring:
datasource:
url: jdbc:mysql://localhost:3306/myapp?useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: your_password
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.example.myapp.model
重点来了:mapper-locations 指向你的 XML 文件目录,type-aliases-package 让你在 XML 里不用写全限定类名,省事!
写个最简单的 CRUD:用户表操作
假设我们有个 user 表:
CREATE TABLE user (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50),
email VARCHAR(100)
);
对应的 Java 实体类:
public class User {
private Long id;
private String name;
private String email;
// getter/setter 省略(其实我用 Lombok,但领导不让,说“调试时看不到字段”)
}
Mapper 接口 + XML 配置
MyBatis 最经典的玩法就是 接口 + XML。先写接口:
@Mapper
public interface UserMapper {
List<User> findAll();
User findById(Long id);
void insert(User user);
void update(User user);
void deleteById(Long id);
}
然后在 src/main/resources/mapper/UserMapper.xml 里写 SQL:
<?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.myapp.mapper.UserMapper">
<select id="findAll" resultType="User">
SELECT * FROM user
</select>
<select id="findById" parameterType="long" resultType="User">
SELECT * FROM user WHERE id = #{id}
</select>
<insert id="insert" parameterType="User" useGeneratedKeys="true" keyProperty="id">
INSERT INTO user(name, email) VALUES(#{name}, #{email})
</insert>
<update id="update" parameterType="User">
UPDATE user SET name=#{name}, email=#{email} WHERE id=#{id}
</update>
<delete id="deleteById" parameterType="long">
DELETE FROM user WHERE id = #{id}
</delete>
</mapper>
几个关键点:
namespace必须和接口全路径一致resultType="User"能用是因为前面配了type-aliases-packageuseGeneratedKeys="true"是为了拿到自增主键,不然user.getId()永远是 null(我第一次就栽这儿,测了半小时以为代码错了)
踩坑实录:那些让我想砸键盘的瞬间
XML 文件没被扫描到
报错:Invalid bound statement (not found)。
原因:mapper-locations路径写错,或者 XML 文件没放在 resources 下。记住:Maven 默认只编译 src/main/resources,别把 XML 放 java 目录里!下划线转驼峰失效
数据库字段是create_time,Java 属性是createTime,结果查出来是 null。
解决:在application.yml加一行:mybatis: configuration: map-underscore-to-camel-case: true事务不生效
我在 Service 里调了两个 insert,结果第二个失败了,第一个却提交了!
原来忘了加@Transactional注解。Spring 的事务是基于 AOP 的,必须加在 public 方法上,且不能 self-invocation(自己调自己)。
性能 & 架构小贴士(来自线上事故的教训)
我们去年双11期间,日志模块突然慢成狗。排查发现是 MyBatis 的 #{} 和 ${} 混用了。
#{}是预编译,防 SQL 注入,推荐用${}是字符串替换,慎用!除非你知道自己在干啥(比如动态表名)
另外,别在循环里调 Mapper 方法!我见过实习生这么写:
for (Long userId : userIds) {
User user = userMapper.findById(userId); // 每次都查 DB!
}
正确做法是用 IN 查询:
List<User> users = userMapper.findByIds(userIds);
对应的 XML:
<select id="findByIds" resultType="User">
SELECT * FROM user WHERE id IN
<foreach collection="list" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
教程之外:怎么系统学习?
说实话,光看网上零散教程容易懵。我后来买了本《MyBatis 从入门到精通》(人民邮电出版社那本),配合官方文档,再跑几个 GitHub 开源项目,才真正搞明白。
如果你是学生党或刚入行,建议走这个路线:
- 先跑通一个完整 Demo(增删改查)
- 学会看 MyBatis 日志(加
logging.level.com.example.mapper=debug) - 尝试集成 PageHelper 做分页
- 了解一级缓存、二级缓存机制(虽然生产环境一般关掉)
- 看源码:SqlSession、Executor、StatementHandler 这几个核心类
最后:前端仔的感悟
作为一个 Vim 党,我习惯在终端里敲命令、看日志。MyBatis 的日志输出特别清晰,每次 SQL 执行、参数绑定都打出来,debug 起来比某些“智能”IDE 友好多了。
成都的生活节奏舒服,加班不多(除了产品临时改需求),这也让我有时间慢慢啃后端。现在我已经能独立接简单后端任务了,虽然离“架构师”还差十万八千里,但至少不会被产品经理一句话吓尿。
MyBatis 不是什么高深技术,但它代表了一种可控的灵活性——你既不用手写 JDBC 处理 ResultSet,也不用被 ORM 框架的魔法束缚。对新人来说,是个很好的中间态。
希望这篇综合教程能帮到和我一样的“转型选手”。如果觉得有用,欢迎留言交流(或者吐槽你们的产品经理)!
附:本文所有代码已上传 GitHub,搜 “mybatis-beginner-chengdu” 即可(假的,别真搜,我还没传 😅)

评论 0