MyBatis 入门:一个前端工程师被逼写后端时的自救指南
上周五晚上十一点,我正窝在工位上改一个双11复盘页面的埋点逻辑,突然钉钉“叮”了一声——不是消息,是视频通话。
产品经理老张的脸瞬间怼满屏幕:“兄弟,你不是会 Java 吗?隔壁组那个接口挂了,他们后端在救火,你能不能临时搭个 CRUD 接口撑到周一?”
我差点把键盘扔了。
我是阿里 P7 前端工程师,坐标北京,每天通勤一小时,主要工作是让页面跑得比用户手速还快。Java?那是大学选修课里让我挂科的语言。但架不住老张一句“你是全栈潜力股啊”,再加上项目 deadline 就在眼前,我只能硬着头皮打开 IDEA,默默祭出 MyBatis。
今天这篇技术分享,就是我在那个凌晨三点、咖啡见底、头发又少三根之后,给所有被迫“跨界”的前端朋友写的 MyBatis 入门实录。
为什么是 MyBatis?而不是 JPA 或 Hibernate?
说实话,一开始我想用 Spring Data JPA——毕竟注解多、代码少,看起来很“前端友好”。但被后端同事无情劝退:“JPA 在高并发场景下太重,SQL 不可控,去年双11我们有个服务就因为 JPA 的 N+1 查询把数据库打崩了。”
MyBatis 胜在轻量、灵活、SQL 可控。它不像 ORM 框架那样全自动映射,而是让你手写 SQL,框架只负责参数绑定和结果集映射。对性能敏感的系统(比如大促期间的订单中心),这种“手动挡”反而更安全。
而且,MyBatis 的 XML 配置方式,对前端来说居然有点亲切——不就是写个带占位符的模板嘛?<select> 标签里塞 SQL,跟 Vue 的 template 差不多(强行类比)。
环境搭建:从“Hello World”到连上数据库
先别急着写业务,先把工具链配好。我用的是:
- JDK 17
- Maven
- MySQL 8.0
- Spring Boot 3.x(集成 MyBatis)
Maven 依赖如下(别抄错,我第一次漏了 mybatis-spring-boot-starter,报了一堆 Bean not found):
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
application.yml 配置数据库连接:
spring:
datasource:
url: jdbc:mysql://localhost:3306/myapp?useSSL=false&serverTimezone=UTC
username: root
password: your_password
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.example.demo.model
重点来了:mapper-locations 指向你的 XML 文件目录,这是 MyBatis 的核心配置之一。
写个最简单的查询:User 表走起
假设我们有张用户表:
CREATE TABLE `user` (
`id` BIGINT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL,
`email` VARCHAR(100)
);
对应的 Java 实体类:
public class User {
private Long id;
private String name;
private String email;
// getter / setter 省略
}
然后创建 Mapper 接口:
@Mapper
public interface UserMapper {
List<User> findAll();
User findById(Long id);
}
注意 @Mapper 注解!没有它,Spring 不会扫描这个接口,你会看到 Invalid bound statement (not found) 这种经典报错——我当时以为是 XML 写错了,其实根本没注册进容器。
再写对应的 XML 文件(放在 resources/mapper/UserMapper.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.demo.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>
</mapper>
关键点:
namespace必须和接口全限定名一致id对应接口方法名#{}是预编译占位符,防 SQL 注入;${}是直接拼接(慎用!)
动态 SQL:别再拼字符串了!
前端同学可能习惯用模板字符串拼请求,但在后端,拼 SQL = 自杀行为。MyBatis 的动态 SQL 才是正道。
比如实现一个带条件的搜索:
List<User> search(@Param("name") String name, @Param("email") String email);
XML 写法:
<select id="search" resultType="User">
SELECT * FROM user
<where>
<if test="name != null and name != ''">
AND name LIKE CONCAT('%', #{name}, '%')
</if>
<if test="email != null and email != ''">
AND email = #{email}
</if>
</where>
</select>
<where> 会自动去掉开头的 AND,避免语法错误。类似的还有 <foreach>(用于 IN 查询)、<choose>(类似 switch)等。
有一次我图省事用 ${} 拼 ORDER BY 字段,结果测试同学输了个 ; DROP TABLE user--,虽然没真删库(权限控制救了我),但被运维拉去喝茶半小时。从此我见到 ${} 就绕道走。
性能优化:别让 MyBatis 成为瓶颈
作为经历过双11洗礼的人,我对性能极其敏感。MyBatis 本身很轻,但用不好照样拖垮系统。
1. 开启二级缓存(谨慎!)
MyBatis 支持一级(SqlSession 级)和二级(Mapper 级)缓存。默认只开一级。
<mapper namespace="...">
<cache />
<!-- 查询语句加 useCache="true" -->
</mapper>
但分布式环境下慎用二级缓存!多个实例共享数据库,缓存容易不一致。我们线上服务全部关掉,靠 Redis 做统一缓存。
2. 批量操作别用循环 insert
前端喜欢 for 循环发请求,后端可不能这么干。MyBatis 提供 <foreach> 实现批量插入:
<insert id="batchInsert">
INSERT INTO user (name, email) VALUES
<foreach collection="list" item="user" separator=",">
(#{user.name}, #{user.email})
</foreach>
</insert>
实测 1000 条数据,单条插入要 8s,批量只要 200ms。算法复杂度从 O(n) 降到接近 O(1)(网络往返减少)。
3. 分页别用 OFFSET
LIMIT 100000, 10 在大数据量下会慢成狗。我们改用游标分页(基于 ID > lastId),配合索引,响应时间稳定在 10ms 内。
生产踩坑记录:那些让我想砸电脑的瞬间
| 问题现象 | 根本原因 | 解决方案 |
|---|---|---|
| 中文乱码 | JDBC URL 没加字符集参数 | ?useUnicode=true&characterEncoding=utf8 |
| 时间差 8 小时 | MySQL 时区 vs JVM 时区不一致 | 统一设为 Asia/Shanghai |
| 事务不回滚 | 方法非 public 或未加 @Transactional |
检查 AOP 代理生效条件 |
| XML 修改不生效 | IDEA 没把 resources 目录标记为资源根 | 右键目录 → Mark as → Resources Root |
最惨的一次:本地测试完美,上线后查不到数据。最后发现是 Linux 服务器文件系统大小写敏感,UserMapper.xml 写成了 usermapper.xml……运维看我的眼神像在看外星人。
前端视角的反思:为什么我要学这个?
说实话,如果不是被逼到墙角,我可能永远不会碰 MyBatis。但这次经历让我意识到:全栈不是会写前后端代码,而是理解系统如何协同工作。
当我知道一条 SQL 从浏览器发起,经过 Nginx、Spring、MyBatis、MySQL 再返回的完整链路,排查问题时就不再只会喊“后端接口慢”。我可以看执行计划、分析慢查询日志、甚至建议 DBA 加索引。
最近我在学 AI,也在思考:未来会不会有 AI 工具自动生成 MyBatis Mapper?但即便如此,理解底层机制的人,才能驾驭工具,而不是被工具驾驭。
结语
MyBatis 入门不难,难的是在高并发、高可用的生产环境中用好它。它不是一个黑盒工具,而是一把需要精心打磨的手术刀。
如果你和我一样,是个被临时抓壮丁的前端,希望这篇文章能帮你少熬两个通宵。如果你是后端老手,欢迎在评论区吐槽我的“前端式理解”——毕竟,技术分享的意义,就在于互相照亮。
对了,那个周五晚上的接口,周一早上顺利交接给了后端团队。老张请我喝了杯瑞幸,说“下次还找你”。我笑着点头,心里默默打开 BOSS 直聘更新了简历。
(完)

评论 0