MyBatis基础教程:Java持久层框架入门

浏览器兼容师
2025-12-15 19:48
阅读 217

上周五晚上十一点,杭州下着小雨,我瘫在工位上盯着屏幕上第37次报错的SQL语句,脑子里只剩下一个念头:“要不转行去卖煎饼吧?”

别误会,我不是被产品经理又改需求气的(虽然他确实刚把“用户登录”从“三天内完成”改成了“今晚上线”),而是被自己写的JDBC代码折磨疯了。每个DAO方法里都是try-catch-finally三件套,ResultSet遍历写得比八股文还规整,结果一个字段名拼错,线上直接500。

说来惭愧,作为一个在阿里和网易之间反复横跳、自称“全栈但主要写后端”的老油条,我一直对MyBatis这种ORM框架嗤之以鼻。以前总觉得:“手写SQL多爽,控制力强,性能好,还能装X。” 直到去年双11期间,我们服务因为DAO层膨胀到2000+行,一个简单的商品查询接口拖慢了整个链路,CTO在晨会上点名:“再不用ORM,就用你的人头祭天。”

那一刻,我终于理解了什么叫“真香”。


为什么是MyBatis?而不是Hibernate、Spring Data JPA,甚至Python的Django ORM?

说到持久层框架,很多人第一反应是对比。毕竟咱们程序员选型,不吵一架都不算完整。

框架 语言 抽象程度 灵活性 学习曲线 杭州大厂使用率
Hibernate Java 高(全自动) 低(HQL限制多) 陡峭 中(偏传统金融)
Spring Data JPA Java 中高 中等 高(尤其Spring Boot项目)
MyBatis Java 中(半自动) 高(直接写SQL) 平缓 极高(阿里系最爱)
Django ORM Python 平缓 低(非主流)
Sequelize / TypeORM JavaScript 极低(前端主导)

你看,Java生态里,MyBatis几乎成了杭州互联网公司的标配——尤其是阿里系。为啥?因为我们既要“敏捷开发”,又要“精细调优”。产品经理今天要加个模糊搜索,明天要联表查用户行为日志,后天还得支持分库分表。这时候,Hibernate那种“你信我,我帮你生成SQL”的哲学就显得有点天真了。

而MyBatis呢?它说:“兄弟,SQL你写,映射我来干。” 这不就是成年人的爱情吗?——给自由,也给兜底


被逼上梁山:我的第一个MyBatis项目

事情起因很简单:公司新接了个ToB项目,要求两周内搭出核心数据模型。数据库设计完,我看着那张包含user_infoorder_recordpayment_log三张主表的ER图,心想:“完了,又要写80个DAO方法。”

但这次我学乖了。打开IDEA,新建Maven项目,pom.xml里加上:

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.13</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.33</version>
</dependency>

然后建了个mybatis-config.xml

<?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/myapp?useSSL=false&amp;serverTimezone=UTC"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <mapper resource="mappers/UserMapper.xml"/>
  </mappers>
</configuration>

接着,写个实体类User.java

public class User {
    private Long id;
    private String username;
    private String email;
    // getter/setter 略
}

重点来了——UserMapper.xml,这才是MyBatis的灵魂:

<?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="findById" parameterType="long" resultType="com.example.model.User">
    SELECT id, username, email FROM user_info WHERE id = #{id}
  </select>

  <insert id="insertUser" parameterType="com.example.model.User">
    INSERT INTO user_info (username, email) VALUES (#{username}, #{email})
  </insert>
</mapper>

最后,在Java代码里调用:

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
    .build(Resources.getResourceAsStream("mybatis-config.xml"));

try (SqlSession session = sqlSessionFactory.openSession()) {
    UserMapper mapper = session.getMapper(UserMapper.class);
    User user = mapper.findById(1L);
    System.out.println(user.getUsername()); // 终于不用手动setXXX了!
}

跑起来那一刻,我差点哭出来——再也不用手动resultSet.getString("username")了!


踩坑实录:那些让我想砸键盘的瞬间

当然,真香之前总有阵痛。

坑1:XML里的&要转义
第一次写带条件的SQL:

SELECT * FROM user WHERE status = 1 AND create_time > '2023-01-01'

结果报错:The entity name must immediately follow the '&' in the entity reference.
后来才知道,XML里&要写成&amp;。现在我看到&就PTSD。

坑2:驼峰命名 vs 下划线命名
数据库字段是create_time,Java属性是createTime,结果查出来是null。
解决方案:在config里加一行:

<settings>
  <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>

坑3:事务没生效
测试插入两条记录,中间抛异常,结果第一条还是入库了。
原来MyBatis默认不开启事务,得手动:

SqlSession session = sqlSessionFactory.openSession(false); // 关闭自动提交
try {
    mapper.insertUser(user1);
    mapper.insertUser(user2);
    session.commit(); // 手动提交
} catch (Exception e) {
    session.rollback(); // 回滚
}

这些坑,每一个都让我深夜对着屏幕骂一句:“早知道用Python了!” —— 但冷静下来想想,Python的Django ORM虽然爽,可一旦要写复杂报表、多表关联、分页优化,照样得原生SQL伺候。语言不是银弹,场景才是。


为什么Java + MyBatis 在“代码人生”中更稳?

说实话,我试过用Node.js写后端,也用Flask搭过小工具。但当你面对百万级QPS、需要精确控制连接池、还要对接Kafka和Flink的时候,Java的生态厚度和稳定性,真的不是闹着玩的

MyBatis在这其中扮演的角色,就像一个“懂你的老伙计”:

  • 它不替你做决定(不像Hibernate自作聪明生成N+1查询)
  • 它允许你写最原始的SQL(性能调优时救命)
  • 它和Spring无缝集成(@MapperScan一行搞定)

更重要的是,在杭州这片卷王之地,会MyBatis几乎等于拿到了面试通行证。我上周帮朋友内推,对方问的第一句就是:“MyBatis的#{}和${}区别能说说吗?”(答案:前者预编译防SQL注入,后者直接拼接——别用后者!)


写在最后:从抵触到拥抱,是成长的开始

曾经我以为,手写SQL是“技术硬核”的象征。
现在我明白,真正的硬核,是在合适的场景用合适的工具,把事情高效、稳定、可维护地做完

MyBatis不是银弹,但它足够灵活、足够透明、足够接地气。它不会让你写出炫酷的函数式代码,也不会让你在GitHub上收获999 stars,但它能让你在凌晨三点改完Bug后,安心回家睡觉——而不是担心明天线上炸了。

所以,如果你还在手写JDBC,或者对ORM框架充满偏见,不妨试试MyBatis。
说不定某天深夜,你也会像我一样,盯着成功返回的JSON数据,喃喃一句:

“这玩意儿……真香。”

(完)

P.S. 产品经理刚发消息说,下周要加Redis缓存。算了,先睡吧,代码人生,且行且珍惜

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝