一个文科生的MyBatis入门实战:从零开始写你的第一个Java数据库程序
大家好,我是小林,曾经是个学历史的文科生。三年前我决定转行做程序员,踩过无数坑,也熬过无数夜。今天我想用最接地气的方式,带你走进 MyBatis 的世界——这个 Java 后端开发中几乎人人必会的数据库框架。
我当初第一次听说“持久层”“ORM”这些词时,脑子里全是问号。但其实,MyBatis 没那么可怕。它就是一个帮你省去写大量重复 JDBC 代码的工具。今天这篇文章,我们就用一个真实的小项目,手把手实现一个能查、能存的用户管理系统,并穿插一些面试题挑战,让你学得扎实、用得放心。
一、MyBatis 是什么?为什么需要它?
简单说:MyBatis 是 Java 中用来操作数据库的框架。
想象一下,你要把一个“用户名”存进 MySQL 数据库。如果不用框架,你得:
- 加载数据库驱动
- 建立连接
- 写 SQL 语句
- 设置参数
- 执行查询
- 处理结果集
- 关闭连接
- 还要处理各种异常……
这一套流程写下来,至少 20 行代码,而且每次操作都要重复!而 MyBatis 把这些“脏活累活”都封装好了,你只需要关注两件事:
- SQL 怎么写
- Java 对象怎么和数据库字段对应
这不仅减少代码量,还大大降低出错概率。
💡 面试题挑战 #1:
MyBatis 和 Hibernate 有什么区别?
简单答:Hibernate 是全自动 ORM(对象关系映映),你几乎不用写 SQL;而 MyBatis 是半自动的,SQL 要你自己写,但更灵活、性能更好,国内企业用得更多。
二、环境准备:5 分钟搭好开发环境
我们使用最经典的组合:Java + Maven + MyBatis + MySQL
1. 安装前提
- JDK 8 或以上(推荐 JDK 11)
- Maven(用于管理依赖)
- MySQL(本地或 Docker 都行)
- 一个 IDE(IntelliJ IDEA 最友好)
2. 创建 Maven 项目
打开终端,执行:
mvn archetype:generate -DgroupId=com.example -DartifactId=mybatis-demo -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
进入项目目录:
cd mybatis-demo
3. 添加依赖(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>
⚠️ 注意:如果你用的是 M1/M2 Mac,MySQL 驱动版本建议 ≥8.0.27,否则可能连不上数据库。
4. 创建数据库和表
在 MySQL 中执行:
CREATE DATABASE mybatis_demo;
USE mybatis_demo;
CREATE TABLE user (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
email VARCHAR(100)
);
插入两条测试数据:
INSERT INTO user (name, email) VALUES ('小林', 'xiaolin@example.com');
INSERT INTO user (name, email) VALUES ('老张', 'zhang@example.com');
三、核心概念:MyBatis 的三大件
MyBatis 虽然功能强大,但初学者只需掌握三个核心部分:
| 组件 | 作用 | 文件示例 |
|---|---|---|
| MyBatis 配置文件 | 告诉 MyBatis 如何连接数据库、加载哪些映射文件 | mybatis-config.xml |
| Mapper 接口 | 定义操作数据库的方法(如 getUserById) | UserMapper.java |
| Mapper XML 文件 | 写具体的 SQL 语句,并映射结果到 Java 对象 | UserMapper.xml |
📌 我当初学的时候,最困惑的就是“为什么要有 XML 文件?”
答案是:解耦!把 SQL 和 Java 代码分开,后期维护、调优、审计都更方便。
四、实战:一步步实现用户查询功能
现在,我们来写一个能“根据 ID 查用户”的功能。
第一步:创建 User 实体类
在 src/main/java/com/example 下新建 User.java:
package com.example;
public class User {
private int id;
private String name;
private String email;
// 必须有无参构造函数(MyBatis 反射需要)
public User() {}
// getter 和 setter
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 配置文件
在 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="your_password"/>
</dataSource>
</environment>
</environments>
<!-- 注册 Mapper XML 文件 -->
<mappers>
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
🔐 安全提示:生产环境中密码不要写死在配置文件里!可以用环境变量或配置中心。
第三步:创建 Mapper 接口
新建 UserMapper.java:
package com.example;
public interface UserMapper {
User selectUserById(int id);
}
第四步:编写 Mapper XML 文件
在 src/main/resources 下创建 UserMapper.xml:
<?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.UserMapper">
<select id="selectUser findById" resultType="com.example.User">
SELECT id, name, email FROM user WHERE id = #{id}
</select>
</mapper>
❗ 注意:
namespace必须和接口全路径一致,id必须和方法名一致!
等等!我发现 XML 里写错了:id="selectUser findById" 应该是 id="selectUserById"。这是新手常犯的错误——方法名和 XML 中的 id 不匹配,会导致运行时报 BindingException。
修正后:
<select id="selectUserById" resultType="com.example.User">
SELECT id, name, email FROM user WHERE id = #{id}
</select>
第五步:写测试代码
在 src/test/java/com/example 下创建 MyBatisTest.java:
package com.example;
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 java.io.InputStream;
public class MyBatisTest {
public static void main(String[] args) throws Exception {
// 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. 调用方法
User user = mapper.selectUserById(1);
System.out.println(user);
}
}
}
运行结果:
User{id=1, name='小林', email='xiaolin@example.com'}
✅ 成功了!
五、扩展:实现插入新用户
现在我们加一个“新增用户”的功能。
1. 在 UserMapper 接口中添加方法
void insertUser(User user);
2. 在 UserMapper.xml 中添加 insert 语句
<insert id="insertUser" parameterType="com.example.User">
INSERT INTO user (name, email) VALUES (#{name}, #{email})
</insert>
3. 测试插入
User newUser = new User();
newUser.setName("小王");
newUser.setEmail("wang@example.com");
mapper.insertUser(newUser);
session.commit(); // 别忘了提交事务!
⚠️ 重要:MyBatis 默认不自动提交事务!增删改操作后必须调用
session.commit(),否则数据不会真正写入数据库。
六、新手常见问题 & 解决方案
| 问题 | 原因 | 解决方法 |
|---|---|---|
ClassNotFoundException: com.mysql.cj.jdbc.Driver |
缺少 MySQL 驱动 | 检查 pom.xml 是否引入了 mysql-connector-java |
BindingException: Invalid bound statement |
Mapper 方法名和 XML 的 id 不一致 | 检查拼写、大小写、命名空间 |
| 插入成功但数据库没数据 | 忘记 commit | 调用 session.commit() |
| 中文乱码 | 数据库连接未指定编码 | 在 URL 后加 &characterEncoding=utf8 |
| 字段名不匹配(如数据库是 user_name,Java 是 userName) | MyBatis 默认按字段名映射 | 使用 @Results 注解或开启驼峰转换 |
💡 开启驼峰转换(推荐):在 mybatis-config.xml 的
<configuration>中加入:<settings> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings>这样
user_name会自动映射到userName。
七、面试题挑战:你能答对几道?
MyBatis 的 #{} 和 ${} 有什么区别?
→#{}是预编译(防 SQL 注入),${}是直接拼接(有风险,慎用)。MyBatis 一级缓存和二级缓存的区别?
→ 一级缓存是 SqlSession 级别(默认开启),二级缓存是 Mapper 级别(需手动开启)。如何实现动态 SQL?
→ 用<if>,<choose>,<foreach>等标签。例如:<select id="findUsers" resultType="User"> SELECT * FROM user <where> <if test="name != null">AND name LIKE CONCAT('%', #{name}, '%')</if> </where> </select>
八、下一步学习建议
你现在已经掌握了 MyBatis 的基础用法!接下来可以:
- 整合 Spring Boot:用
mybatis-spring-boot-starter自动配置,告别 XML。 - 学习注解方式:用
@Select,@Insert等注解替代 XML。 - 掌握分页插件:如 PageHelper,轻松实现分页查询。
- 了解 MyBatis-Plus:国产增强版,CRUD 几乎不用写 SQL。
🌟 最后送你一句话:技术没有捷径,但有正确的路径。我从连“什么是主键”都不知道,到现在能带团队做微服务项目,靠的就是每天写一点代码、解决一个问题。你也可以。
动手试试吧!把今天的代码跑通,就是你迈向 Java 后端工程师的第一步。

评论 0