← 返回上一页

第1章: MyBatis 入门

用最简单的方式操作数据库 —— 告别繁琐的 JDBC

学习进度 0/6

一句话理解 MyBatis

🍽️ 比喻:点菜 vs 自己做饭

🥵 原生 JDBC(自己做饭)
  • 自己买菜 → 加载驱动
  • 自己洗菜 → 获取连接
  • 自己切菜 → 拼接 SQL 字符串
  • 自己炒菜 → 设置参数
  • 自己装盘 → 遍历 ResultSet
  • 自己洗碗 → 关闭连接
😵 一个查询写 30 行代码
😎 MyBatis(点菜)
  • 写好菜单 → 写 SQL(你最擅长的)
  • 告诉服务员 → 调用 Mapper 方法
  • 坐等上菜 → 自动返回 Java 对象
🚀 你只管写 SQL,其他全自动!

MyBatis 帮你省了什么?

🔌
自动管理连接
不用自己写 getConnection()、close(),MyBatis 帮你管理连接池。
📝
SQL 与代码分离
SQL 写在 XML 或注解里,Java 代码干净清爽,改 SQL 不用改代码。
🔄
自动映射结果
查询结果自动变成 Java 对象(User、Order...),不用手动 rs.getString()
动态 SQL
根据条件自动拼接 SQL,再也不用写一堆 if-else 拼字符串 了。

互动体验:JDBC vs MyBatis 代码对比

🎮 同样是「根据 ID 查询用户」,代码量差多少?
点击按钮对比两种写法...

MyBatis 核心组件(记住这 4 个就够了)

🏗️
SqlSessionFactoryBuilder
读配置文件
→ 创建工厂
用完即丢
🏭
SqlSessionFactory
工厂
→ 生产 Session
全局唯一(单例)
🔗
SqlSession
一次数据库会话
→ 获取 Mapper
用完就关(一次请求一个)
📋
Mapper
你定义的接口
→ 调用方法=执行SQL
跟 Session 同生命周期
💡 一句话记住生命周期:

Builder 建工厂(用完丢)→ 工厂生产 Session(全局一个工厂)→ Session 获取 Mapper(一个请求一个 Session)→ Mapper 执行 SQL

跟我做:5 分钟跑通第一个 MyBatis 项目

⚠️ 我们直接用 Spring Boot + MyBatis!

实际开发中没人单独用 MyBatis,都是配合 Spring Boot 使用。下面的步骤复制粘贴就能运行

1
创建 Spring Boot 项目,添加依赖

在 Spring Initializr 中勾选:Spring Web + MyBatis Framework + MySQL Driver

<!-- 📄 pom.xml — 关键依赖(Spring Initializr 自动生成) --> <dependencies> <!-- Web 开发 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- ⭐ MyBatis 整合 Spring Boot 的 starter --> <!-- 一个 starter 就搞定了:MyBatis + 数据源 + 事务管理 --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.2</version> </dependency> <!-- MySQL 驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> </dependencies>
2
配置数据库连接

编辑 application.yml(把用户名密码改成你自己的):

# 📄 application.yml — 数据库 + MyBatis 配置 # 数据源配置(改成你自己的数据库信息) spring: datasource: url: jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC username: root # 你的 MySQL 用户名 password: 123456 # 你的 MySQL 密码 driver-class-name: com.mysql.cj.jdbc.Driver # MyBatis 配置 mybatis: mapper-locations: classpath:mapper/*.xml # XML 文件放在 resources/mapper/ 目录下 type-aliases-package: com.example.entity # 实体类包名(XML 里可以用短名) configuration: map-underscore-to-camel-case: true # ⭐ 下划线自动转驼峰(user_name → userName) log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 控制台打印 SQL(调试用)
3
准备数据库表

在 MySQL 中执行以下 SQL:

-- 📄 建表 SQL — 复制到 MySQL 执行 CREATE DATABASE IF NOT EXISTS mydb; USE mydb; CREATE TABLE users ( id BIGINT PRIMARY KEY AUTO_INCREMENT, -- 主键,自增 username VARCHAR(50) NOT NULL, -- 用户名 email VARCHAR(100), -- 邮箱 age INT, -- 年龄 create_time DATETIME DEFAULT NOW() -- 创建时间(自动填充) ); -- 插入几条测试数据 INSERT INTO users(username, email, age) VALUES ('张三', 'zhangsan@qq.com', 25), ('李四', 'lisi@qq.com', 30), ('王五', 'wangwu@qq.com', 28);
4
创建项目文件

按照以下结构创建文件:

src/main/java/com/example/
├── Application.java         ← 主启动类(已有)
├── entity/
│ └── User.java            ← 实体类(对应数据库表)
├── mapper/
│ └── UserMapper.java      ← Mapper 接口(定义方法)
└── controller/
    └── UserController.java ← 控制器(测试接口)

src/main/resources/
├── application.yml
└── mapper/
    └── UserMapper.xml       ← SQL 映射文件
5
编写代码(4 个文件)

文件 ①:实体类 User.java

// 📄 User.java — 实体类,一个字段对应数据库一列 package com.example.entity; public class User { private Long id; // 对应 users 表的 id 列 private String username; // 对应 users 表的 username 列 private String email; // 对应 users 表的 email 列 private Integer age; // 对应 users 表的 age 列 // getter/setter(必须有!MyBatis 通过它们给字段赋值) public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } // toString(打印用) @Override public String toString() { return "User{id=" + id + ", username='" + username + "', age=" + age + "}"; } }

文件 ②:Mapper 接口 UserMapper.java

// 📄 UserMapper.java — Mapper 接口 // 你只需要定义方法,MyBatis 自动帮你实现!(动态代理) package com.example.mapper; import com.example.entity.User; import org.apache.ibatis.annotations.*; import java.util.List; @Mapper // ⭐ 告诉 Spring:这是一个 MyBatis 的 Mapper,帮我创建实现类 public interface UserMapper { // 查询所有用户(SQL 写在 XML 中) List<User> findAll(); // 根据 ID 查询(SQL 写在 XML 中) User findById(Long id); // ====== 也可以用注解直接写 SQL(简单 SQL 推荐) ====== // 插入用户,并把自增 ID 回填到 user.id @Insert("INSERT INTO users(username, email, age) VALUES(#{username}, #{email}, #{age})") @Options(useGeneratedKeys = true, keyProperty = "id") int insert(User user); // 更新用户 @Update("UPDATE users SET username=#{username}, email=#{email}, age=#{age} WHERE id=#{id}") int update(User user); // 删除用户 @Delete("DELETE FROM users WHERE id = #{id}") int delete(Long id); }

文件 ③:Mapper XML(复杂 SQL 写这里)

<!-- 📄 resources/mapper/UserMapper.xml — SQL 映射文件 --> <?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"> <!-- namespace 必须等于 Mapper 接口的全类名(这样 MyBatis 才能把 XML 和接口对应起来) --> <mapper namespace="com.example.mapper.UserMapper"> <!-- id = 接口中的方法名,resultType = 返回的 Java 类型 --> <!-- #{id} = 方法参数,MyBatis 自动做防 SQL 注入处理 --> <!-- 查询所有用户 --> <select id="findAll" resultType="com.example.entity.User"> SELECT * FROM users ORDER BY id DESC </select> <!-- 根据 ID 查询单个用户 --> <select id="findById" resultType="com.example.entity.User"> SELECT * FROM users WHERE id = #{id} </select> </mapper>

文件 ④:Controller(用来测试)

// 📄 UserController.java — 测试接口 package com.example.controller; import com.example.entity.User; import com.example.mapper.UserMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.List; @RestController @RequestMapping("/api/users") public class UserController { @Autowired private UserMapper userMapper; // Spring 自动注入 MyBatis 生成的实现类 // GET /api/users → 查询所有 @GetMapping public List<User> findAll() { return userMapper.findAll(); } // GET /api/users/1 → 根据 ID 查询 @GetMapping("/{id}") public User findById(@PathVariable Long id) { return userMapper.findById(id); } // POST /api/users → 新增用户 @PostMapping public User insert(@RequestBody User user) { userMapper.insert(user); // 插入数据库 return user; // id 已自动回填! } // PUT /api/users/1 → 更新用户 @PutMapping("/{id}") public String update(@PathVariable Long id, @RequestBody User user) { user.setId(id); userMapper.update(user); return "更新成功"; } // DELETE /api/users/1 → 删除用户 @DeleteMapping("/{id}") public String delete(@PathVariable Long id) { userMapper.delete(id); return "删除成功"; } }
6
运行并测试!

启动 Application.main(),浏览器打开 http://localhost:8080/api/users

看到 JSON 数据就成功了 🎉

互动:MyBatis SQL 执行模拟器

模拟调用 Mapper 方法,看看 MyBatis 在背后做了什么:

📋 选择要执行的操作:
📝 你写的 Java 代码
选择操作...
⚡ MyBatis 实际执行的 SQL
等待执行...
📦 返回结果
等待结果...

XML 还是注解?怎么选

XML 方式 注解方式 怎么选?
✅ 适合复杂 SQL(动态查询、多表联查等)
<!-- XML 方式:SQL 写在 XML 文件中 --> <select id="findByCondition" resultType="User"> SELECT * FROM users <where> <if test="username != null"> AND username LIKE CONCAT('%', #{username}, '%') </if> <if test="age != null"> AND age = #{age} </if> </where> ORDER BY id DESC </select>
✅ SQL 和 Java 代码完全分离
✅ 支持动态 SQL 标签(if/where/foreach)
✅ IDE 有 SQL 高亮和提示
✅ 适合简单 CRUD(一行就搞定)
// 注解方式:SQL 直接写在接口方法上 @Mapper public interface UserMapper { @Select("SELECT * FROM users WHERE id = #{id}") User findById(Long id); @Insert("INSERT INTO users(username, email, age) VALUES(#{username}, #{email}, #{age})") @Options(useGeneratedKeys = true, keyProperty = "id") int insert(User user); @Update("UPDATE users SET username=#{username} WHERE id=#{id}") int update(User user); @Delete("DELETE FROM users WHERE id = #{id}") int delete(Long id); }
✅ 简单快速,不用创建 XML 文件
❌ 不支持动态 SQL(if/where 等标签)
❌ 复杂 SQL 会让注解很难看
🎯 实际开发的最佳实践

简单 SQL 用注解(单表的增删改查,一行 SQL 就搞定的)

复杂 SQL 用 XML(动态查询、多表联查、批量操作)

两种可以混用!同一个 Mapper 里,有些方法用注解,有些方法用 XML,完全 OK。

💡 面试常问:MyBatis 注解和 XML 的区别?答:注解简单快速但不支持动态SQL;XML 功能完整支持动态SQL标签;实际开发中两种混合使用。

📝 学完检测

第 1 题:MyBatis 中全局唯一、负责创建 SqlSession 的是?
A. SqlSession
B. SqlSessionFactory
C. SqlSessionFactoryBuilder
D. Mapper
第 2 题:#{id} 和 ${id} 的区别是?
A. 没有区别,都一样
B. #{} 是预编译(防注入),${} 是字符串拼接(有注入风险)
C. ${} 更安全
D. #{} 只能用在 XML,${} 只能用在注解
第 3 题:XML 中 mapper 的 namespace 属性应该填什么?
A. 随便起个名字
B. 数据库表名
C. Mapper 接口的全类名
D. 实体类的全类名

本章小结

← 返回上一页 下一章: 动态SQL →