乐途乐途
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
  • 学习路径
  • 第1章 MyBatis概述与快速上手

    • 本章定位
    • MyBatis简介
    • 环境搭建
    • 第一个MyBatis程序
    • SqlSessionFactoryBuilder与openSession重载
    • SqlSessionFactory与SqlSession
    • SqlSession核心方法
    • 不使用 XML 构建 SqlSessionFactory
    • Mapper接口与映射方式
    • Java API 目录结构
  • 第2章 全局配置文件详解

    • 本章定位
    • properties
    • settings
    • typeAliases
    • typeHandlers
    • objectFactory
    • plugins
    • environments
    • transactionManager
    • dataSource
    • databaseIdProvider
    • mappers
    • 日志配置
  • 第3章 SQL映射文件基础

    • 本章定位
    • select
    • insert
    • update
    • delete
    • 参数传递与占位符
    • 主键生成策略
    • resultType
    • resultMap
    • 自动映射详解
    • sql片段
    • SQL 语句构建器
  • 第4章 动态SQL

    • 本章定位
    • if
    • choose、when、otherwise
    • where
    • set
    • foreach
    • trim
    • bind
    • script 元素:在注解映射器中启用动态 SQL
    • _databaseId 与动态 SQL 的多数据库支持
    • 动态 SQL 中插入脚本语言
  • 第5章 结果映射与关联查询

    • 本章定位
    • resultMap详解
    • association
    • collection
    • discriminator
    • N+1查询问题
    • 延迟加载
  • 第6章 MyBatis注解开发

    • 本章定位
    • @Select
    • @Insert
    • @Update
    • @Delete
    • @Param
    • @Options
    • @SelectKey
    • @Results
    • @Result
    • @One
    • @Many
    • @SelectProvider
  • 第7章 缓存与性能优化

    • 本章定位
    • 一级缓存
    • 二级缓存
    • 缓存配置详解
    • 自定义缓存
    • Executor执行器类型
    • 分页插件

MyBatis简介

导学

通过本节学习,你将能够:

  • 准确描述 MyBatis 在 Java 技术栈中的定位与职责
  • 对比 JDBC、MyBatis、Hibernate 三种持久层方案的核心差异
  • 理解 MyBatis "SQL 与代码解耦" 的设计哲学
  • 判断实际项目中何时选择 MyBatis 而非其他 ORM 框架

定义

什么是 MyBatis

MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码、参数设置和结果集获取工作,通过简单的 XML 或注解即可将原始类型、接口和 Java POJO 映射为数据库中的记录。

它解决了什么痛点

在 MyBatis 出现之前,Java 开发者直接使用 JDBC 访问数据库,面临以下典型痛苦:

痛点JDBC 原始写法带来的问题
SQL 散落在代码中字符串拼接在 Java 代码里修改 SQL 需重新编译部署
参数手动绑定ps.setInt(1, id)、ps.setString(2, name)参数多了极易错位,维护困难
结果集手动提取rs.getInt("id")、rs.getString("name")列名变更后到处改代码
无内置缓存每次查询都走数据库性能差,重复查询浪费资源
异常处理繁琐每个操作都要 try-catch-finally代码臃肿,资源泄漏风险高

MyBatis 的核心价值:让开发者专注于 SQL 本身,而将参数绑定、结果映射、资源管理等重复劳动交给框架。


核心原理

MyBatis 核心组件关系

MyBatis 的运行时架构由一系列职责清晰的组件构成,它们协同完成从 Java 方法调用到 SQL 执行、结果返回的完整流程:

组件职责说明:

组件职责作用域
SqlSessionFactory创建 SqlSession 的工厂,解析全局配置应用级,全局唯一
SqlSession与数据库交互的会话,执行 SQL请求级,线程不安全
ExecutorSQL 执行器,调度 StatementHandler会话级
StatementHandler封装 JDBC Statement 操作语句级
ParameterHandler将 Java 参数转换为 JDBC 参数语句级
ResultSetHandler将 JDBC 结果集转换为 Java 对象语句级
一级缓存SqlSession 级别的缓存,默认开启会话级
二级缓存Mapper 级别的缓存,需手动配置命名空间级

与 JDBC、Hibernate 的对比

维度JDBCMyBatisHibernate
SQL 控制完全手写,硬编码在 Java 中手写 SQL,XML/注解管理,与代码解耦自动生成 HQL/JPQL,或 Criteria API
参数映射手动 ps.setXXX()#{} 自动类型映射全自动字段映射
结果映射手动 rs.getXXX()resultMap/resultType 自动映射全自动 ORM 映射
缓存机制无内置缓存一级缓存 + 二级缓存多级缓存体系
学习曲线低,但 API 繁琐中等,需掌握 XML/注解配置高,需理解对象状态、HQL
灵活性极高,但代价是重复代码高,SQL 完全可控中,复杂 SQL 需原生查询
适用场景超轻量、极致性能调优企业级应用,SQL 需优化和审计快速开发,CRUD 为主

MyBatis 的核心理念可以概括为三句话:

  1. 不对应用程序或数据库强加影响 —— 不强制你改变数据库设计,也不强制你改变 Java 对象设计
  2. SQL 写在 XML 里与代码解耦 —— 运维人员可直接审阅和调优 SQL,无需重新编译 Java 代码
  3. 提供映射标签支持 ORM 字段关系映射 —— 复杂关联查询(一对一、一对多)可通过 resultMap 优雅处理

完整示例

场景说明

乐途公司技术部要开发一个学生管理系统,需要查询学生信息。我们先看 JDBC 原始写法,再看 MyBatis 写法,直观感受差异。

操作前的数据库表结构及初始数据

CREATE TABLE student (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(20),
    age INT,
    major VARCHAR(20),
    score DECIMAL(5,2)
);

INSERT INTO student (name, age, major, score) VALUES
('大翔', 22, '计算机科学', 95.5),
('白歌', 21, '软件工程', 88.0),
('小崔', 20, '计算机科学', 92.0),
('黄俪', 21, '信息安全', 90.5),
('李眉', 22, '软件工程', 87.0);

当前数据状态:

idnameagemajorscore
1大翔22计算机科学95.50
2白歌21软件工程88.00
3小崔20计算机科学92.00
4黄俪21信息安全90.50
5李眉22软件工程87.00

JDBC 原始写法(痛点展示)

public Student findById_JDBC(int id) {
    String sql = "SELECT id, name, age, major, score FROM student WHERE id = ?";
    Student student = null;
    
    // 1. 加载驱动、获取连接 —— 样板代码
    try (Connection conn = DriverManager.getConnection(
            "jdbc:mysql://localhost:3306/school", "root", "123456");
         PreparedStatement ps = conn.prepareStatement(sql)) {
        
        // 2. 手动设置参数 —— 参数多了极易错位
        ps.setInt(1, id);
        
        // 3. 执行查询
        try (ResultSet rs = ps.executeQuery()) {
            if (rs.next()) {
                student = new Student();
                // 4. 手动提取结果集 —— 列名变更后到处改
                student.setId(rs.getInt("id"));
                student.setName(rs.getString("name"));
                student.setAge(rs.getInt("age"));
                student.setMajor(rs.getString("major"));
                student.setScore(rs.getBigDecimal("score"));
            }
        }
    } catch (SQLException e) {
        // 5. 异常处理 —— 每个方法都要写
        e.printStackTrace();
    }
    // 6. 连接、语句、结果集都要手动关闭 —— 遗漏即泄漏
    return student;
}

MyBatis 写法(框架托管)

StudentMapper.xml

<?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.fly.mapper.StudentMapper">
    
    <!-- SQL 与 Java 代码解耦,参数自动映射,结果自动封装 -->
    <select id="findById" resultType="com.fly.entity.Student">
        SELECT id, name, age, major, score 
        FROM student 
        WHERE id = #{id}
    </select>
    
</mapper>

Java 调用代码

public Student findById_MyBatis(int id) {
    try (SqlSession session = sqlSessionFactory.openSession()) {
        // 一行代码完成:参数绑定、SQL 执行、结果映射、资源释放
        StudentMapper mapper = session.getMapper(StudentMapper.class);
        return mapper.findById(id);
    }
}

实际执行结果及分析

执行 findById(1) 后控制台输出:

==>  Preparing: SELECT id, name, age, major, score FROM student WHERE id = ?
==> Parameters: 1(Integer)
<==    Columns: id, name, age, major, score
<==        Row: 1, 大翔, 22, 计算机科学, 95.50
<==      Total: 1

返回的 Java 对象:

属性值
id1
name大翔
age22
major计算机科学
score95.50

对比分析:

维度JDBC 写法MyBatis 写法
代码行数约 25 行约 5 行
SQL 位置硬编码在 Java 中独立在 XML 中
参数处理手动 ps.setInt(1, id)自动 #{id}
结果映射手动 5 个 rs.getXXX()自动 resultType
资源释放手动 try-finally自动 try-with-resources
可维护性差优

易错场景 / 常见误区

误区错误认知正解
MyBatis 是全自动 ORM以为不需要写 SQLMyBatis 是半自动 ORM,SQL 必须自己写,框架只负责映射和托管
MyBatis 比 Hibernate 落后认为自动生成 SQL 更高级复杂业务、SQL 优化场景下,手写 SQL 是优势而非劣势
用 MyBatis 就不用懂 JDBC完全忽视底层原理排查连接泄漏、死锁、SQL 注入等问题时,JDBC 知识必不可少
所有项目都用 MyBatis技术选型一刀切纯 CRUD 后台、快速原型可考虑 Hibernate/JPA;遗留系统、复杂查询优选 MyBatis

面试考点

Q1:MyBatis 与 Hibernate 的核心区别是什么?什么时候选 MyBatis?

A: MyBatis 是半自动 ORM,SQL 由开发者手写,通过 XML/注解配置参数映射和结果映射,灵活性高,适合 SQL 需要精细优化、审计或频繁变更的场景。Hibernate 是全自动 ORM,通过 HQL/JPQL 或 Criteria 自动生成 SQL,开发效率高,适合以 CRUD 为主、数据库结构稳定的业务系统。当项目需要 DBA 审阅 SQL、存在大量多表关联复杂查询、或数据库设计不完全遵循对象模型时,优先选择 MyBatis。

Q2:MyBatis 的 #{} 和 ${} 有什么区别?

A: #{} 是预编译处理,MyBatis 会将其替换为 ? 占位符,通过 PreparedStatement 设置参数,能防止 SQL 注入,适用于传入普通参数值。${} 是字符串直接替换,将参数原样拼接到 SQL 中,存在 SQL 注入风险,仅用于传入表名、列名等不能预编译的场景。

Q3:为什么说 MyBatis 不对应用程序或数据库强加影响?

A: MyBatis 不要求数据库表结构与 Java 对象严格一一对应(可通过 resultMap 灵活映射),也不要求开发者必须使用某种特定的对象设计模式。它只负责将开发者手写的 SQL 与 Java 方法进行绑定,并自动完成参数和结果的转换,数据库设计和应用设计保持独立。

Q4:MyBatis 的一级缓存和二级缓存有什么区别?

A: 一级缓存是 SqlSession 级别的缓存,默认开启,生命周期与 SqlSession 相同,会话关闭即清空,主要用于避免同一会话内的重复查询。二级缓存是 Mapper 命名空间级别的缓存,需要手动在 XML 中配置 <cache/>,多个 SqlSession 可共享,适用于读多写少、数据变更不频繁的场景。


小结

本节从 JDBC 的繁琐痛点出发,介绍了 MyBatis 作为半自动 ORM 框架的定位:它让开发者保留对 SQL 的完全控制权,同时将参数绑定、结果映射、资源管理等重复工作交给框架。通过与 JDBC、Hibernate 的横向对比,我们明确了 MyBatis 的适用边界。核心组件关系图展示了 MyBatis 内部的协作架构,为后续深入各组件打下基础。

关键记忆点:

  • MyBatis = 手写 SQL + 自动映射 + 资源托管
  • 半自动 ORM 的核心优势:SQL 可控、与代码解耦、学习曲线适中
  • 四大核心组件:SqlSessionFactory → SqlSession → Executor → StatementHandler

下一章引子

了解了 MyBatis "是什么" 和 "为什么用" 之后,下一步就是动手实践。下一节将带你完成 MyBatis 的环境搭建——从 Maven 依赖引入、mybatis-config.xml 核心配置,到标准项目目录结构的建立。准备好 IDE,我们即将写出第一个可运行的 MyBatis 程序。

上一页
本章定位
下一页
环境搭建