别再被ORM吓退!MyBatis零基础入门实战指南
你好,我是你们的技术培训负责人老张。带过上百名应届生,深知刚接触后端开发时面对“持久层”、“ORM”这些词的茫然感。我当初学的时候,光是配个数据库连接就折腾了一整天——不是驱动版本不对,就是XML路径写错。更别提面试官冷不丁问一句:“MyBatis和Hibernate有什么区别?”当场懵圈。
今天这篇教程,就是专为完全零基础的同学准备的。哪怕你连JDBC都没碰过,只要会写简单的Java类,就能跟着做下去。我们会用最直白的语言、最真实的代码、最常见的坑,带你亲手跑通第一个MyBatis程序。
顺便说一句:虽然标题里有“Python”,但本文主角是Java生态的MyBatis。之所以提到Python,是因为很多转行同学是从Python过来的(比如我带过的不少数据方向转后端的同学),会在对比中产生困惑。文末我会专门聊聊这点。
为什么选MyBatis?它到底是什么?
简单说:MyBatis是一个帮Java程序和数据库“对话”的工具。
想象一下,你想从MySQL里查一个用户信息。不用框架的话,你得:
- 加载数据库驱动
- 建立连接(Connection)
- 写SQL字符串
- 创建Statement或PreparedStatement
- 执行查询
- 遍历ResultSet把数据塞进Java对象
- 关闭各种资源……
光是第6步,字段名对不上、类型转换出错,就够你调试半天。而MyBatis把这些脏活累活全包了——你只需专注两件事:
- 写SQL(对,你没看错,MyBatis让你直接写SQL!)
- 定义Java对象和数据库表的映射关系
这正是它比Hibernate更受国内企业欢迎的原因:灵活、可控、性能透明。很多大厂面试题都会考:“为什么项目选用MyBatis而不是JPA?” 答案往往就是这两个字:掌控力。
环境准备:5分钟搭好开发环境
⚠️ 注意:本教程基于 Java 8+、Maven、MySQL 5.7+。如果你用的是IDEA,会更顺畅。
第一步:创建Maven项目
打开IDEA → New Project → 选择Maven → 勾选“Create from archetype” → 选maven-archetype-quickstart。
输入:
- GroupId:
com.example - ArtifactId:
mybatis-demo
点Finish。等待项目初始化完成。
第二步:添加依赖(pom.xml)
在pom.xml的<dependencies>里加入以下内容:
<!-- MyBatis核心 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.13</version>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<!-- 单元测试(可选但推荐) -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
保存后,IDEA会自动下载依赖。如果卡住,检查网络或手动刷新Maven。
第三步:准备数据库
登录MySQL,执行:
CREATE DATABASE mybatis_demo;
USE mybatis_demo;
CREATE TABLE user (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50),
email VARCHAR(100)
);
INSERT INTO user (name, email) VALUES
('张三', 'zhangsan@example.com'),
('李四', 'lisi@example.com');
记下你的数据库用户名和密码(假设是root/123456)。
核心概念:三件套搞定MyBatis
MyBatis的核心配置就三个文件,我称之为“铁三角”:
| 文件 | 作用 | 位置 |
|---|---|---|
mybatis-config.xml |
全局配置:数据库连接、插件等 | src/main/resources |
UserMapper.java |
接口:定义操作数据库的方法 | src/main/java/com/example/mapper |
UserMapper.xml |
SQL映射:写具体SQL语句 | src/main/resources |
下面一一详解。
1. 全局配置文件:mybatis-config.xml
在src/main/resources下新建mybatis-config.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://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/mybatis_demo?useSSL=false&serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!-- 注册Mapper XML文件 -->
<mappers>
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
💡 踩坑提示:
&是XML里的转义写法,实际URL中是&。- 如果报“时区错误”,确保加了
serverTimezone=UTC。- 驱动类名在MySQL 8+是
com.mysql.cj.jdbc.Driver,不是旧的com.mysql.jdbc.Driver!
2. 定义实体类:User.java
在 src/main/java/com/example/model 下创建:
package com.example.model;
public class User {
private int id;
private String name;
private String email;
// 必须要有无参构造器!MyBatis通过反射创建对象
public User() {}
// getter/setter省略(IDEA可自动生成)
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
@Override
public String toString() {
return "User{id=" + id + ", name='" + name + "', email='" + email + "'}";
}
}
⚠️ 新手常犯错误:忘记写无参构造器!MyBatis底层用反射
new User(),没有无参构造会报错。
3. Mapper接口与XML:解耦SQL与Java
先创建接口 UserMapper.java(在 com.example.mapper 包下):
package com.example.mapper;
import com.example.model.User;
import java.util.List;
public interface UserMapper {
List<User> findAll();
User findById(int id);
void insert(User user);
void update(User user);
void delete(int id);
}
再创建对应的 UserMapper.xml(放在 src/main/resources):
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.UserMapper">
<!-- 结果映射:告诉MyBatis如何把数据库列转成Java属性 -->
<resultMap id="UserResultMap" type="com.example.model.User">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="email" column="email"/>
</resultMap>
<!-- 查询所有用户 -->
<select id="findAll" resultMap="UserResultMap">
SELECT * FROM user
</select>
<!-- 根据ID查询 -->
<select id="findById" parameterType="int" resultMap="UserResultMap">
SELECT * FROM user WHERE id = #{id}
</select>
<!-- 插入用户 -->
<insert id="insert" parameterType="com.example.model.User">
INSERT INTO user (name, email) VALUES (#{name}, #{email})
</insert>
<!-- 更新用户 -->
<update id="update" parameterType="com.example.model.User">
UPDATE user SET name = #{name}, email = #{email} WHERE id = #{id}
</update>
<!-- 删除用户 -->
<delete id="delete" parameterType="int">
DELETE FROM user WHERE id = #{id}
</delete>
</mapper>
🔑 关键点解释:
namespace必须和接口全类名一致!#{}是MyBatis的占位符,会自动防SQL注入(类似PreparedStatement)。resultMap用于复杂映射(比如列名和属性名不一致时)。这里简单场景其实可以用resultType="User"直接映射,但养成用resultMap的习惯更安全。
实战:跑通第一个MyBatis程序
现在,我们写一个测试类来验证一切是否正常。
在 src/test/java/com/example 下创建 MyBatisTest.java:
package com.example;
import com.example.mapper.UserMapper;
import com.example.model.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class MyBatisTest {
@Test
public void testFindAll() throws IOException {
// 1. 读取配置文件
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
// 2. 构建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 3. 获取SqlSession(代表一次数据库会话)
try (SqlSession session = sqlSessionFactory.openSession()) {
// 4. 获取Mapper接口的代理实现
UserMapper mapper = session.getMapper(UserMapper.class);
// 5. 调用方法
List<User> users = mapper.findAll();
for (User user : users) {
System.out.println(user);
}
}
}
@Test
public void testInsert() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
try (SqlSession session = sqlSessionFactory.openSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
User newUser = new User();
newUser.setName("王五");
newUser.setEmail("wangwu@example.com");
mapper.insert(newUser);
// ⚠️ 重要:MyBatis默认不会自动提交事务!
session.commit();
System.out.println("插入成功,新ID: " + newUser.getId()); // 注意:此时ID还是0!
}
}
}
运行 testFindAll(),你应该看到控制台输出两个用户信息。
💡 踩坑重点:
- 必须调用
session.commit()!否则插入/更新不会生效。这是新手最高频的“为什么数据没变?”问题。- 插入后想拿到自增ID?需要在
<insert>标签里加属性:这样<insert id="insert" useGeneratedKeys="true" keyProperty="id">newUser.getId()才能拿到数据库生成的ID。
新手高频问题解答(附真实面试题)
Q1:MyBatis和Hibernate有什么区别?(经典面试题!)
| 对比项 | MyBatis | Hibernate |
|---|---|---|
| SQL控制 | 开发者写SQL,完全掌控 | 自动生成SQL,黑盒感强 |
| 学习曲线 | 简单,会SQL就能上手 | 复杂,需理解Session、缓存等概念 |
| 性能优化 | 直接优化SQL即可 | 需要懂HQL、缓存策略等 |
| 适用场景 | 高并发、复杂查询、遗留系统 | 快速开发、简单CRUD、新项目 |
📌 面试回答技巧:
“我们项目选MyBatis,因为DBA要求SQL必须经过审核,且部分查询涉及多表复杂关联,手写SQL更高效。”
Q2:为什么我的XML文件改了没生效?
90%是因为IDE没把resources目录标记为资源目录!
解决:右键 src/main/resources → Mark Directory as → Resources Root。
Q3:Python开发者常有的困惑
很多从Python转来的同学会问:“Django ORM那么方便,MyBatis还要写XML,是不是落后了?”
答:不是落后,是权衡。
- Python的GIL限制了多线程性能,所以Django靠ORM简化开发没问题。
- Java常用于高并发场景,MyBatis让开发者能精确控制SQL,避免ORM生成低效查询拖垮数据库。
记住:没有银弹,只有合适场景。
Q4:#{xxx} 和 ${xxx} 有什么区别?
#{xxx}→ PreparedStatement占位符,自动防SQL注入${xxx}→ 字符串拼接,有SQL注入风险!
除非动态表名/列名(如分表),否则永远用 #{}!
下一步学习建议
恭喜你完成了MyBatis入门!但真正的工程化使用远不止这些。建议按顺序深入:
- 整合Spring Boot:告别手动管理SqlSession,用
@MapperScan自动注入。 - 学习动态SQL:
<if>,<foreach>等标签处理条件查询。 - 掌握缓存机制:一级缓存(SqlSession级)、二级缓存(Mapper级)。
- 分页插件:PageHelper是国产神器,几行代码实现物理分页。
- 逆向工程:用MyBatis Generator自动生成Mapper和实体类。
最后送你一句我常对应届生说的话:
“框架只是工具,SQL才是后端工程师的硬通货。”
把MyBatis当桥梁,真正去理解索引、事务、锁这些数据库核心知识,你才能在面试中脱颖而出。
现在,去跑通你的第一个MyBatis程序吧!遇到问题,欢迎回来翻这篇“避坑指南”。

评论 0