MyBatis概述

92 阅读5分钟

MyBatis 是一款灵活 ORM 框架,支持动态 SQL、对象映射及缓存机制,核心组件包括 SqlSessionFactory、Mapper 和 Executor,适用于复杂 SQL 优化、遗留数据库适配及高性能批量操作场景,强调对 SQL 的精细控制。

一、MyBatis 核心特性

1. SQL 与代码解耦

  • 特性说明 MyBatis 通过 XML 或注解将 SQL 从 Java 代码中分离,便于维护和复用。

  • 示例

    <!-- UserMapper.xml -->
    <select id="selectUserById" resultType="User">
        SELECT id, name, age FROM user WHERE id = #{id}
    </select>
    

2. 动态 SQL

  • 特性说明 支持根据条件动态拼接 SQL,避免手动拼接字符串的繁琐和 SQL 注入风险。

  • 核心标签 <if>, <choose>, <foreach>, <where>, <set>

  • 示例

    <select id="findUsers" parameterType="map" resultType="User">
        SELECT * FROM user
        <where>
            <if test="name != null">
                AND name = #{name}
            </if>
            <if test="age != null">
                AND age = #{age}
            </if>
        </where>
    </select>
    

3. 对象关系映射(ORM)

  • 特性说明 通过 ResultMap 将数据库字段与 Java 对象属性映射,支持复杂对象(嵌套对象、集合)。

  • 示例

    <resultMap id="userWithOrdersMap" type="User">
        <id property="id" column="user_id"/>
        <result property="name" column="user_name"/>
        <!-- 一对多关联 -->
        <collection property="orders" ofType="Order">
            <id property="orderId" column="order_id"/>
            <result property="amount" column="order_amount"/>
        </collection>
    </resultMap>
    

4. 接口绑定

  • 特性说明 通过 Mapper 接口定义操作,MyBatis 自动生成实现类(基于动态代理),无需手动编写 DAO。

  • 示例

    public interface UserMapper {
        @Select("SELECT * FROM user WHERE id = #{id}")
        User selectUserById(int id);
    }
    

5. 缓存机制

  • 一级缓存

    • 默认开启,基于 SqlSession 生命周期,同一会话中重复查询直接复用缓存。
    • 失效场景:执行 insert/update/delete 或调用 clearCache()
  • 二级缓存

    • 需手动开启,跨 SqlSession 共享,适用于全局数据缓存。
    • 配置方式:在 Mapper XML 中添加 <cache/> 标签。
    • 注意事项:实体类需实现 Serializable 接口。

二、MyBatis 核心组件

1. SqlSessionFactory

  • 作用 全局单例工厂,用于创建 SqlSession

  • 配置方式

    • 通过 mybatis-config.xml 文件配置数据源、插件、类型处理器等。
    • 与 Spring 集成时,使用 SqlSessionFactoryBean
  • 示例

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="mapperLocations" value="classpath:mapper/*.xml"/>
    </bean>
    

2. SqlSession

  • 作用 代表一次数据库会话,线程不安全,需确保及时关闭(通常通过 try-with-resources 或 Spring 管理)。

  • 核心方法

    • selectOne(), selectList():查询单条或多条数据。
    • insert(), update(), delete():执行写操作。
    • commit(), rollback():手动提交或回滚事务。
  • 示例

    try (SqlSession session = sqlSessionFactory.openSession()) {
        UserMapper mapper = session.getMapper(UserMapper.class);
        User user = mapper.selectUserById(1);
    }
    

3. Mapper 接口与 XML 映射文件

  • Mapper 接口 定义数据库操作方法,方法名与 XML 中的 SQL ID 对应。

  • XML 映射文件 编写 SQL 语句与映射规则,通过 <mapper> 标签关联接口。

  • 示例

    <mapper namespace="com.example.mapper.UserMapper">
        <select id="selectUserById" resultType="User">
            SELECT * FROM user WHERE id = #{id}
        </select>
    </mapper>
    

4. Executor

  • 作用 SQL 执行器,负责处理 SQL 请求,MyBatis 提供三种类型:

    1. SimpleExecutor:默认,每次执行创建新的 Statement
    2. ReuseExecutor:复用 Statement,减少资源消耗。
    3. BatchExecutor:批量执行 SQL,提升写入性能。
  • 配置方式 在全局配置中设置 defaultExecutorType

    <settings>
        <setting name="defaultExecutorType" value="BATCH"/>
    </settings>
    

三、MyBatis 使用场景

1. 复杂 SQL 优化

  • 场景说明 需要手动编写高效 SQL,如多表关联、子查询、窗口函数等。

  • 示例

    <select id="getSalesReport" resultType="map">
        SELECT 
            u.name, 
            SUM(o.amount) AS total_amount,
            RANK() OVER (ORDER BY SUM(o.amount) DESC) AS rank
        FROM user u
        JOIN orders o ON u.id = o.user_id
        GROUP BY u.id
    </select>
    

2. 遗留数据库适配

  • 场景说明 数据库表结构与对象模型不一致时,通过 ResultMap 灵活映射。

  • 示例

    <resultMap id="legacyUserMap" type="User">
        <id property="id" column="old_user_id"/>
        <result property="name" column="legacy_name"/>
    </resultMap>
    

3. 高性能批量操作

  • 场景说明 使用 BatchExecutor 执行批量插入或更新,减少数据库交互次数。

  • 示例

    try (SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH)) {
        UserMapper mapper = session.getMapper(UserMapper.class);
        for (User user : userList) {
            mapper.insertUser(user);
        }
        session.commit();
    }
    

4. 动态条件查询

  • 场景说明 根据前端传入的条件动态生成 WHERE 子句,如电商平台的商品筛选。

  • 示例

    <select id="searchProducts" resultType="Product">
        SELECT * FROM product
        <where>
            <if test="category != null">
                AND category = #{category}
            </if>
            <if test="minPrice != null">
                AND price >= #{minPrice}
            </if>
            <if test="maxPrice != null">
                AND price <= #{maxPrice}
            </if>
        </where>
    </select>
    

四、解决的问题

MyBatis 是一个基于 Java 的持久层框架,主要解决了传统 JDBC 开发中的以下核心问题:


1. 简化 JDBC 繁琐操作

  • 问题:直接使用 JDBC 需要手动处理连接获取、SQL 拼接、结果集映射、异常处理等大量样板代码,开发效率低下且易出错。

  • 解决方案

    • 自动管理连接:通过配置数据源,自动处理连接的获取和释放。
    • SQL 与代码解耦:将 SQL 语句定义在 XML 或注解中,避免在 Java 代码中硬编码。
    • 自动结果映射:将数据库查询结果自动映射到 Java 对象(POJO),无需手动遍历 ResultSet

2. 提供灵活的对象关系映射(ORM)

  • 问题:全自动 ORM 框架(如 Hibernate)生成的 SQL 不可控,复杂查询或优化困难。

  • 解决方案

    • 开发者控制 SQL:允许手动编写 SQL,确保查询效率和准确性。
    • 动态 SQL:通过 <if>, <foreach>, <choose> 等标签,根据条件动态生成 SQL,避免 Java 代码中的字符串拼接。
    • 支持复杂映射:通过 <resultMap> 定义字段与对象的映射关系,处理数据库字段名与 Java 属性名不一致的情况。

3. 实现 SQL 与业务逻辑分离

  • 问题:JDBC 中 SQL 嵌入在 Java 代码中,导致代码臃肿、可读性差且难以维护。

  • 解决方案

    • XML 或注解配置:将 SQL 定义在独立的 XML 文件或注解中,业务逻辑聚焦在 Java 类中。
    • 模块化设计:按功能划分 Mapper 接口和 XML 文件,提高代码可维护性。

4. 支持事务管理与集成

  • 问题:JDBC 需要手动管理事务(提交、回滚),且难以与框架整合。

  • 解决方案

    • 与 Spring 无缝集成:通过 SqlSessionFactoryBean 等组件,轻松整合 Spring 的事务管理(如 @Transactional)。
    • 声明式事务:简化事务边界的定义,避免侵入式代码。

5. 提高开发效率与可维护性

  • 问题:传统 JDBC 开发重复劳动多,团队协作成本高。

  • 解决方案

    • 代码生成工具:通过 MyBatis Generator 自动生成基础 CRUD 代码。
    • 插件扩展:支持分页插件(PageHelper)、性能监控等工具,快速增强功能。

五、总结

  • 核心特性:SQL 解耦、动态 SQL、灵活 ORM、接口绑定、缓存机制。
  • 核心组件SqlSessionFactory(全局工厂)、SqlSession(会话)、Mapper(接口与 XML)、Executor(执行器)。
  • 适用场景:复杂 SQL 优化、遗留系统适配、高性能批量操作、动态查询需求。

优势:对 SQL 的完全控制权,适合需要精细化操作数据库的场景; 劣势:相比全自动 ORM(如 Hibernate),需编写更多 SQL 和映射配置。