裸辞半年后,我用 MyBatis 重新敲开了 Spring Boot 的门

南城开发者
2026-01-04 16:12
阅读 1074

去年十月,我从某一线大厂裸辞了。
不是因为被裁,也不是因为卷不动——纯粹是觉得“再这样下去,代码写得再好,也救不了自己快熄灭的热情”。Gap 半年,白天看书、健身、陪猫,晚上则常常窝在电脑前,一行行敲着代码。说来奇怪,越是不用打卡的日子,我写代码反而越高效。可能是因为没有产品经理半夜甩过来的“紧急需求”,也没有运维同学在群里@全体成员说“线上又挂了”。

但 Gap 不是躺平。最近开始重新投简历,面试官一开口就是:“Spring Boot + MyBatis 用得熟吗?讲讲一级缓存和二级缓存的区别?”
我:……(内心 OS:这不就是我在家撸的那套玩意儿吗!)

于是决定写点东西,既是复习,也是给同样在找工作的兄弟们一点参考。今天就聊聊 MyBatis ——这个在 Java 持久层里低调但稳如老狗的框架。


为什么不是 JPA?为什么是 MyBatis?

在大厂那会儿,我们团队用的是 MyBatis,而不是 Spring Data JPA。原因很简单:可控性

JPA 写起来确实爽,findByUserIdAndStatus() 这种方法名直接生成 SQL,省事。但一旦业务复杂起来——比如要写多表关联、动态条件、分页加排序、甚至手写窗口函数——JPA 就容易“翻车”。而 MyBatis 把 SQL 明确写在 XML 或注解里,每一行 SQL 都是你亲手写的,出了问题你背锅,但也意味着你能精准调优

尤其是在双11这种大促期间,DBA 看到你传过去的慢查询语句,能直接骂到你工位上。这时候,一个清晰、可读、可维护的 SQL 文件,比什么都重要。


Spring Boot + MyBatis:三分钟跑通不是梦

先别想什么缓存、插件、分页,先让项目跑起来。这是我 Gap 期间在家搭的第一个 Demo,用的是 Spring Boot 3.x + MyBatis 3.5+。

1. 引入依赖(Maven)

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>3.0.3</version>
</dependency>
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>

别忘了配数据源!我一开始忘了加 spring.datasource.url,启动时报 Failed to configure a DataSource,差点以为 Spring Boot 嫌弃我失业太久不配连数据库 😅

2. 实体类 + Mapper 接口

public class User {
    private Long id;
    private String name;
    private String email;
    // getter/setter 略
}
@Mapper
public interface UserMapper {
    @Select("SELECT * FROM users WHERE id = #{id}")
    User selectById(Long id);

    @Insert("INSERT INTO users(name, email) VALUES(#{name}, #{email})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    int insert(User user);
}

注意 @Options(useGeneratedKeys = true) —— 这是获取自增主键的关键。很多新人面试被问“插入后怎么拿 ID”,答不上来就凉了。其实就这一行配置。


XML 还是注解?我的选择是……

我知道现在很多人喜欢用注解写 SQL,觉得“少一个 XML 文件,清爽”。但我坚持用 XML,原因有三:

  1. SQL 复杂时,注解里写多行字符串太丑(尤其带动态 WHERE
  2. XML 支持 <include><trim> 等标签,复用性强
  3. 团队协作时,SQL 和 Java 逻辑分离,DBA 更容易 review

举个真实场景:产品要求“用户列表支持按姓名模糊查、按邮箱精确查、按状态筛选,三个条件可选”。用注解写?试试看:

@Select("<script>" +
        "SELECT * FROM users " +
        "<where>" +
        "<if test='name != null'>AND name LIKE CONCAT('%', #{name}, '%')</if>" +
        "<if test='email != null'>AND email = #{email}</if>" +
        "<if test='status != null'>AND status = #{status}</if>" +
        "</where>" +
        "</script>")
List<User> queryUsers(@Param("name") String name, 
                      @Param("email") String email, 
                      @Param("status") Integer status);

是不是看着就想砸键盘?换成 XML:

<select id="queryUsers" resultType="User">
    SELECT * FROM users
    <where>
        <if test="name != null">AND name LIKE CONCAT('%', #{name}, '%')</if>
        <if test="email != null">AND email = #{email}</if>
        <if test="status != null">AND status = #{status}</if>
    </where>
</select>

干净、清晰、可维护。这就是我坚持 XML 的理由。


缓存?别被面试题带偏了

说到 MyBatis,面试必问:“一级缓存和二级缓存有什么区别?”

  • 一级缓存:SqlSession 级别,默认开启。同一个 SqlSession 中,重复查询会走缓存。
  • 二级缓存:Mapper 级别,需手动开启,跨 SqlSession 共享。

但我要泼冷水:生产环境慎用二级缓存

为啥?因为 MyBatis 的二级缓存是基于 namespace 的,一旦多个服务实例共享数据库(比如微服务架构),缓存脏读风险极高。我们大厂曾经有个事故:用户改了资料,但其他节点读的还是旧缓存,客服电话被打爆。

所以我的建议是:

  • 一级缓存:默认就行,别动
  • 二级缓存:除非你明确知道自己在做什么,否则关掉
  • 真要缓存?上 Redis,配合 Cache-Aside 模式,更安全

可读性 > 聪明:我的代码人生信条

Gap 期间重看以前写的代码,发现有些地方为了“炫技”用了复杂的嵌套 resultMap 或自定义 TypeHandler,结果三个月后自己都看不懂。现在我写 MyBatis,只遵循一条原则:让接手的人一眼看懂你在干啥

比如关联查询,宁愿多查一次,也不写三层嵌套的 <collection>。性能差?加个 Redis 补回来。但可读性丢了,团队协作成本就上去了。

这也是我在面试时特别看重的一点:代码是给人看的,其次才是给机器跑的。很多候选人能把 MyBatis 源码讲得头头是道,但写出的 XML 像天书——这种人,我不敢要。


附:MyBatis 常见面试题速查表

问题 关键点
一级 vs 二级缓存 作用域、是否默认开启、线程安全
#{} ${} 区别 #{} 预编译防注入,${} 直接拼接(慎用!)
如何获取自增主键? @Options(useGeneratedKeys=true, keyProperty="id")
动态 SQL 标签有哪些? <if>, <choose>, <foreach>, <set>, <trim>
如何防止 SQL 注入? 永远用 #{},避免 ${};输入校验

记住:${} 是 SQL 注入的入口!除非你 100% 信任输入(比如枚举值),否则别碰。


最后:Gap 不是空白,是蓄力

这半年,我没荒废。每天深夜写代码,不是为了卷,而是找回那种“一行代码改变世界”的感觉。MyBatis 虽然老,但它稳定、透明、可控——就像一个靠谱的老同事。

下周就要去新公司入职了,技术栈依然是 Spring Boot + MyBatis。这次,我想把代码写得更 clean 一点,把文档写得更清楚一点,把坑填得更早一点。

毕竟,代码人生,不在快,而在稳

祝所有正在找工作的朋友,早日拿到 offer。
也祝我自己,在下一段旅程里,少些加班,多些热爱。

评论 0

最热最新
暂无评论
南城开发者Lv.1
0
影响力
0
文章
0
粉丝