MyBatis

详情

1. 是什么?

MyBatis 是一个开源的 持久层框架(Persistence Framework),用于简化 Java 应用与关系型数据库之间的交互。

MyBatis 只实现了 ORM 中的“M”(Mapping)部分,而没有实现“O-R”之间的自动同步与抽象。

所以严格来说它不是 ORM(对象关系映射)框架(不像 Hibernate 那样全自动映射),而是一个 SQL 映射框架(SQL Mapping Framework)。

它的核心思想是:开发者手写 SQL,MyBatis 负责将 SQL 的输入参数和输出结果自动映射到 Java 对象。

官方定义:MyBatis 是一个支持自定义 SQL、存储过程以及高级映射的优秀持久层框架。它避免了几乎所有的 JDBC 样板代码,同时保留了对 SQL 的完全控制。

关键特点:

  • SQL 与 Java 代码分离(通常写在 XML 文件或注解中)
  • 自动将 ResultSet 映射为 Java 对象(POJO)
  • 支持动态SQL(如 <if>, <foreach> 等标签)
  • 轻量、灵活、性能高

2. 没有之前?

在 MyBatis 出现之前(其前身是 Apache iBATIS,2002 年发布,2010 年更名为 MyBatis),Java 开发者主要依赖 原生 JDBC 访问数据库,存在以下问题:

问题说明
大量样板代码每次都要写 ConnectionPreparedStatementResultSet 的获取、关闭、异常处理等。
结果集手动映射需要逐字段从 ResultSet 中取值并赋给 Java 对象,重复且易错。
SQL 与业务逻辑耦合SQL 字符串硬编码在 Java 类中,难以维护、测试和复用。
动态 SQL 困难条件查询需拼接字符串,容易出错且不安全(如 SQL 注入风险)。
资源管理复杂必须确保连接、语句、结果集正确关闭,否则可能内存泄漏。

3. 为什么使用?

使用 MyBatis 的核心价值在于 在保留 SQL 控制力的同时,消除 JDBC 的样板代码。

  • SQL 完全可控:开发者手写 SQL,可优化、调试、复用,适合复杂查询。
  • 减少样板代码:自动处理连接、参数设置、结果映射、资源关闭。
  • 灵活的结果映射:支持一对一、一对多、嵌套结果、列别名自动匹配属性等。
  • 强大的动态 SQL:通过 XML 标签(<if>, <choose>, <foreach>)构建条件查询,安全且清晰。
  • 轻量级 & 高性能:无运行时代理、无复杂缓存机制(除非显式配置),启动快、开销小。
  • 易于集成:可与 Spring、Spring Boot 无缝整合。
  • 学习成本低:相比 Hibernate,概念更少,上手更快。

适用场景:需要精细控制 SQL 的系统(如报表、大数据查询)、遗留系统改造、对性能敏感的应用。

4. 核心组件 / 概念

组件/概念说明
SqlSessionFactory重量级、线程安全的工厂类,用于创建 SqlSession。通常应用启动时初始化一次。
SqlSession轻量级、非线程安全的会话对象,提供执行 SQL、获取 Mapper、管理事务的方法。
Mapper 接口纯 Java 接口,方法对应 SQL 操作。MyBatis 通过动态代理实现接口,无需编写实现类。
Mapper XML 文件定义 SQL 语句和结果映射规则(如 <select>, <resultMap>)。文件名需与 Mapper 接口对应。
SqlSessionTemplate(Spring 中)Spring 封装的线程安全 SqlSession,用于替代原始 SqlSession。
TypeHandler类型处理器,用于 Java 类型与 JDBC 类型之间的转换(如枚举、JSON 字段)。
ResultMap最强大的元素之一,用于定义复杂的结果映射(如关联对象、集合、列名与属性名不一致等)。
动态 SQL 标签<if>, <where>, <foreach>, <set> 等,用于构建条件性 SQL。

5. 使用步骤

步骤 1:添加依赖(Maven)

<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>
<!-- 若使用 Spring Boot -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>3.0.3</version>
</dependency>

步骤 2:配置 MyBatis(mybatis-config.xml 或 Java Config)

<!-- 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/mydb"/>
                <property name="username" value="root"/>
                <property name="password" value="password"/>
            </dataSource>
        </environment>
    </environments>
 
    <!-- 注册 Mapper XML 文件 -->
    <mappers>
        <mapper resource="mappers/UserMapper.xml"/>
    </mappers>
</configuration>

步骤 3:定义实体类(POJO)

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

步骤 4:定义 Mapper 接口

public interface UserMapper {
    User findById(Long id);
    List<User> findByName(String name);
    void insert(User user);
    void update(User user);
    void delete(Long id);
}

步骤 5:编写 Mapper XML 文件(UserMapper.xml

<!-- resources/mappers/UserMapper.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.example.mapper.UserMapper">
 
    <select id="findById" resultType="com.example.model.User">
        SELECT id, name, email FROM users WHERE id = #{id}
    </select>
 
    <select id="findByName" resultType="User">
        SELECT * FROM users
        <where>
            <if test="name != null and name != ''">
                AND name LIKE CONCAT('%', #{name}, '%')
            </if>
        </where>
    </select>
 
    <insert id="insert" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO users (name, email) VALUES (#{name}, #{email})
    </insert>
 
    <update id="update">
        UPDATE users
        <set>
            <if test="name != null">name = #{name},</if>
            <if test="email != null">email = #{email},</if>
        </set>
        WHERE id = #{id}
    </update>
 
    <delete id="delete">
        DELETE FROM users WHERE id = #{id}
    </delete>
 
</mapper>

步骤 6:使用 MyBatis(主程序)

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
 
public class Main {
    public static void main(String[] args) throws Exception {
        // 1. 加载配置
        var inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
 
        // 2. 获取 SqlSession
        try (SqlSession session = sqlSessionFactory.openSession()) {
            // 3. 获取 Mapper
            UserMapper mapper = session.getMapper(UserMapper.class);
 
            // 4. 执行操作
            User user = new User();
            user.setName("Bob");
            user.setEmail("bob@example.com");
            mapper.insert(user);
            session.commit(); // 提交事务
 
            User saved = mapper.findById(user.getId());
            System.out.println(saved.getName()); // 输出 Bob
        }
    }
}

在 Spring Boot 中,只需加 @MapperScanapplication.yml 配置,即可自动注入 Mapper。

6. 局限性(Limitations)

尽管 MyBatis 灵活高效,但也存在一些不足:

局限说明
需要手写 SQL对简单 CRUD 场景显得“重”,不如 JPA/Hibernate 自动生成方便。
数据库移植性差SQL 写死在 XML/注解中,切换数据库需重写 SQL(如 MySQL 分页 vs Oracle ROWNUM)。
无对象关系自动管理不支持懒加载、脏检查、级联保存等 ORM 特性,关联对象需手动处理。
XML 维护成本大型项目中 Mapper XML 文件可能非常多,管理复杂。
类型安全弱XML 中的 SQL 和参数名是字符串,编译期无法检查错误(但可通过 MyBatis Generator 缓解)。
缓存机制较弱一级缓存(SqlSession 级)默认开启,二级缓存需手动配置且使用谨慎。
不适合快速原型开发相比 Spring Data JPA,需要更多配置和文件。

关联网络

演化日志

  • v0.1 (2024-02-26):初始版本
  • v0.2 (2026-02-02):补充关联网络、演化日志

待办事项