本文信息核实于2026-08-06
先给你交个底:我见过太多程序员在MyBatis上栽跟头,不是因为它难,而是因为网上教程太散、太旧、太坑。今天这篇,我不扯官方文档那套官话,直接把我这几年用MyBatis踩过的雷、优化过的方案、面试被追问的细节,一次性全倒给你。看完你至少能少走三个月弯路。
核心观点:MyBatis不是简单的SQL映射工具,而是一个需要你“带着脑子”用的持久层框架。用好了它是神器,用不好它是灾难。
一、为什么我劝你别再用“纯JDBC”和“Hibernate”死磕?
我知道你心里可能嘀咕:“我直接用JDBC写SQL不也挺爽?Hibernate全自动映射不也省事?” 兄弟,你要是还在这么想,说明你还没经历过这些场景:
- 你写JDBC,光是处理
ResultSet到对象的映射,就能写到手抽筋,尤其是当你的表有20个字段的时候。 - 你写Hibernate,确实省事,但一旦遇到复杂的多表联查、动态SQL、分页优化,Hibernate生成的SQL能把你气死,性能问题让你在线上环境被运维追着骂。
而MyBatis,它就是一个“半自动”的聪明人。它把SQL的控制权完全交给你,同时又帮你把结果映射、参数绑定这些脏活累活干了。简单说:SQL你写,映射它来。这就是它能在国内互联网公司占据半壁江山的原因。
二、MyBatis核心三板斧:配置、Mapper、动态SQL
咱们不聊虚的,直接上干货。你要想用好MyBatis,就盯死这三样东西。
1. 配置文件别死记,理解“数据源”和“环境”就够用
很多人一上来就被mybatis-config.xml里那一堆标签吓住了。别慌,你只需要记住:
<environments>:就是配置数据库连接的地方,开发、测试、生产环境可以切换。<mappers>:这里告诉MyBatis去哪里找你的SQL映射文件(就是Mapper.xml)。
我的建议:配置用Spring Boot整合后,这些XML配置大多可以简化成application.yml里的几行代码。但底层逻辑你一定要懂,不然报错你都不知道去哪查。
2. Mapper接口和XML的“爱恨情仇”
这是MyBatis的灵魂。一个UserMapper接口,对应一个UserMapper.xml文件。接口里定义方法,XML里写SQL。
- 命名空间(namespace):必须写,而且要写接口的全限定名,不然MyBatis找不到。
- ID:必须和接口方法名一致。
- 参数:用
#{}占位符,它会帮你预编译,防止SQL注入。这是铁律,永远不要用${}去拼接用户输入的数据,除非你想被脱库。
3. 动态SQL,这是MyBatis给你的“核武器”
你写SQL最烦什么?是不是“where 1=1”这种丑到哭的写法?MyBatis的<if>、<where>、<choose>、<foreach>标签就是来解决这个的。
举个例子,你要做一个多条件查询,用户可能传姓名,可能传邮箱,可能什么都不传:
<select id="findByCondition" resultType="User">
SELECT * FROM user
<where>
<if test="name != null and name != ''">
AND name = #{name}
</if>
<if test="email != null">
AND email = #{email}
</if>
</where>
</select>
看到没?<where>标签会自动处理掉多余的AND。这才是优雅的SQL写法。你要是还在用where 1=1,赶紧改过来,会被同行笑话的。
三、进阶避坑指南:这5个坑,90%的人都踩过
接下来这部分是重点,是我用真金白银(加班时间)换来的教训。
坑1:返回主键到底怎么搞?
插入数据后,你总得拿到自增主键吧?很多人写半天selectKey,麻烦死了。MyBatis其实有更简单的:
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
INSERT INTO user (name, email) VALUES (#{name}, #{email})
</insert>
加个useGeneratedKeys="true",指定keyProperty,主键就自动回填到你的实体类id字段里了。简单不?
坑2:多表联查,结果映射别用resultType硬怼
一旦你联查两张表,字段多了,resultType就会让你写一堆别名,累死。这时候要用resultMap。它就像是一个“翻译官”,把数据库的字段翻译成你Java对象的属性。
<resultMap id="UserOrderMap" type="User">
<id property="id" column="user_id"/>
<result property="name" column="user_name"/>
<collection property="orders" ofType="Order">
<id property="id" column="order_id"/>
<result property="price" column="order_price"/>
</collection>
</resultMap>
这玩意儿虽然写起来啰嗦,但性能最好,也最清晰。记住,复杂查询用resultMap,简单查询用resultType,这是黄金法则。
坑3:分页插件别乱选,就用PageHelper
分页是刚需。别自己写LIMIT,麻烦且容易出错。直接用PageHelper,它是国内用得最多的MyBatis分页插件。
PageHelper.startPage(pageNum, pageSize);
List<User> users = userMapper.findAll();
PageInfo<User> pageInfo = new PageInfo<>(users);
三行代码搞定分页,连总条数都给你查好了。但注意:PageHelper.startPage后面必须紧跟第一条SQL查询语句,中间不能穿插其他数据库操作,不然分页就失效了,这是个经典坑。
坑4:缓存机制,别乱开二级缓存
MyBatis有一级缓存(默认开启,SqlSession级别)和二级缓存(需要手动开启,Mapper级别)。一级缓存问题不大,但二级缓存,我劝你谨慎。因为如果你开了二级缓存,又用了多表联查,缓存的数据可能因为其他表的更新而变得不一致。到时候出现脏读,你哭都来不及。我的建议是:默认不开,除非你非常清楚自己在做什么。
坑5:参数传递,别用Map当万能药
很多人图省事,方法参数直接传一个Map。这确实灵活,但可读性太差。过三个月你自己看代码都不知道那个map.get("xxx")是什么。我的建议是:单参数直接传,多参数用@Param注解,或者封装成一个DTO对象。 代码是写给人看的,不是写给机器看的。
四、关于MyBatis,你可能会问的5个问题(FAQ)
Q1:MyBatis和MyBatis-Plus到底选哪个? A:如果你是新项目,且不需要写特别复杂的SQL,直接用MyBatis-Plus。它内置了单表CRUD方法,能省你70%的重复代码。但如果你需要复杂的多表动态SQL,底层还是得靠MyBatis的XML。所以,MyBatis-Plus是增强,不是替代。
Q2:用MyBatis Generator生成代码靠谱吗? A:靠谱,但生成的代码只能当“初稿”。它生成的Mapper和实体类能满足最基本的CRUD,但复杂业务SQL还是得自己写。我的建议是:用它生成基础代码,然后自己动手改。
Q3:Mapper接口和XML文件怎么保证对应上?
A:记住两点:第一,接口的全限定名和XML的namespace一致;第二,接口的方法名和XML的SQL的id一致。只要这两点对了,基本就绑定了。另外,Spring Boot下建议在application.yml里配置mapper-locations: classpath:mapper/*.xml,把XML文件放在resources/mapper目录下。
Q4:SQL日志怎么看?
A:在application.yml里配置:
mybatis:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
这样控制台会打印所有执行的SQL和参数,排查问题必备。
Q5:MyBatis的性能怎么样?会不会比JDBC慢? A:MyBatis本身就是基于JDBC封装的,SQL执行性能几乎和手写JDBC一样。它主要的时间开销在反射映射上,但这点开销可以忽略不计。真正影响性能的是你写的SQL本身,别甩锅给框架。
五、给你的实用建议(建议收藏)
最后,我给你一套可以直接上手的“组合拳”:
- 新项目:直接上
Spring Boot + MyBatis-Plus,用MyBatis-Plus的LambdaQueryWrapper写单表查询,用@Select注解写简单SQL,复杂SQL才去写XML。 - 老项目:如果还在用纯MyBatis,别急着重构,先把
resultMap和动态SQL用熟练,把PageHelper用起来,性能优化先看慢SQL日志。 - 学习路径:先看官方文档的“Getting Started”,然后找一个开源项目(比如
mall、ruoyi)看别人是怎么写Mapper的,最后自己动手写一个简单的博客系统练手。 - 面试准备:一定要能说清楚
#{}和${}的区别,resultType和resultMap的区别,一级缓存和二级缓存的区别。这三个问题几乎是必问的。 - 避坑心态:遇到问题别急着百度,先看SQL日志,再检查参数绑定,最后再怀疑框架。90%的MyBatis问题都是SQL写错了,不是框架的锅。
最后说句掏心窝的:MyBatis这玩意儿,就像一把瑞士军刀,功能强大,但需要你了解它的脾气。别指望看一遍文档就会了,多写、多踩坑、多总结,你才能真正驾驭它。
如果你觉得这篇文章有用,别光收藏,转发给你身边还在被MyBatis折磨的同事,一起进步才是真的进步。有问题评论区见,我看到了会回。