Java 持久层框架 MyBatis 全面详解

一、介绍

MyBatis 是一款持久层框架,原名为 iBatis,2010 年由 Apache 迁移到 Google Code 并更名,2013 年又迁移到 GitHub。它消除了几乎所有的 JDBC 代码、手动设置参数和获取结果集的操作,通过XML 或注解的方式将 SQL 与 Java 代码解耦,支持自定义 SQL、存储过程和高级映射,是 Java 生态中主流的 ORM(对象关系映射)框架之一。

特点:

  1. 轻量级 & 灵活:相比 Hibernate 等全自动化 ORM 框架,MyBatis 不强制封装所有 SQL,允许开发者手写 SQL,适配复杂业务场景(如多表联查、复杂条件筛选)。
  2. SQL 与代码解耦:SQL 可集中管理在 XML 文件中,便于维护和优化(DBA 可直接修改 SQL 无需改动代码)。
  3. 强大的映射能力:支持一对一、一对多、多对多等复杂关系映射,无需手动封装结果集。
  4. 减少 JDBC 冗余代码:自动处理连接获取、参数设置、结果集解析、连接关闭等操作,避免手动管理导致的错误。
  5. 动态 SQL:提供 <if><where><foreach> 等标签,可根据条件动态拼接 SQL,解决拼接 SQL 时的空格、逗号等问题。
补充:

什么是ORM?

对象关系映射(ORM,Object-Relational Mapping)是一种编程技术,它的核心是把 “数据库中的表 / 记录” 和 “编程语言中的对象 / 实例” 做对应,让开发者可以用 “操作对象” 的方式来操作数据库,无需直接写 SQL(或减少 SQL 的编写)。

简单说:

数据库里的表 → 对应编程语言里的类;

表中的一行记录 → 对应类的一个对象实例;

表中的字段 → 对应类的属性;

对数据库的增删改查 → 对应对对象的创建、修改、删除、查询。

MyBatis 执行流程:

Java 持久层框架 MyBatis 全面详解

二、核心组件

1. SqlSessionFactory

  • 作用:创建 SqlSession 的工厂类,是 MyBatis 的核心入口,全局唯一(通常通过单例模式创建)。
  • 创建方式:通过 SqlSessionFactoryBuilder 解析 MyBatis 核心配置文件(mybatis-config.xml)或自定义配置类生成。

2. SqlSession

  • 作用:代表与数据库的一次会话,是执行 SQL 的核心对象,提供了增删改查的方法(如 selectOneinsertupdate 等)。
  • 生命周期:单次请求 / 方法级别,用完需及时关闭(否则会导致连接泄漏)。
  • 注意:SqlSession 不是线程安全的,不能在多线程中共享。

3. Mapper 接口(映射器)

  • 作用:MyBatis 采用 “接口 + XML / 注解” 的方式定义 SQL,Mapper 接口是 SQL 操作的抽象层,无需实现类(MyBatis 动态生成代理类)。
  • 示例:

public interfadce UserMapper {
// 通过注解定义SQL
@Select(“SELECT * FROM user WHERE id = #{id}”)
User selectUserById(Long id);

// 通过XML定义SQL(推荐复杂SQL)
List<User> selectUserByCondition(UserCondition condition);
}

4. 核心配置文件(mybatis-config.xml)

MyBatis 的全局配置文件,包含环境(数据源、事务)、类型别名、插件、映射器等核心配置:

<?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”/> <!– 事务管理:JDBC/MANAGED –>
<dataSource type=”POOLED”> <!– 数据源:POOLED/UNPOOLED/JNDI –>
<property name=”driver” value=”com.mysql.cj.jdbc.Driver”/>
<property name=”url” value=”jdbc:mysql://localhost:3306/test?useSSL=false”/>
<property name=”username” value=”root”/>
<property name=”password” value=”123456″/>
</dataSource>
</environment>
</environments>
<!– 映射器:指定Mapper接口或XML文件位置 –>
<mappers>
<mapper resource=”mapper/UserMapper.xml”/>
<!– 或通过接口包扫描 –>
<!– <package name=”com.example.mapper”/> –>
</mappers>
</configuration>

5. Mapper XML 文件

存放 SQL 语句和结果映射规则,核心标签包括:

<select>:查询语句

<insert>:插入语句

<update>:更新语句

<delete>:删除语句

<resultMap>:自定义结果集映射(解决字段名与实体属性名不一致、关联查询等)

示例(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”>
<!– namespace对应Mapper接口全类名 –>
<mapper namespace=”com.example.mapper.UserMapper”>
<!– 自定义结果映射:解决字段名(如user_name)与属性名(userName)不一致 –>
<resultMap id=”UserResultMap” type=”com.example.entity.User”>
<id column=”id” property=”id”/> <!– 主键映射 –>
<result column=”user_name” property=”userName”/>
<result column=”age” property=”age”/>
<result column=”create_time” property=”createTime” jdbcType=”TIMESTAMP”/>
</resultMap>

<!– 查询:引用自定义resultMap,参数通过#{参数名}接收 –>
<select id=”selectUserById” resultMap=”UserResultMap”>
SELECT id, user_name, age, create_time FROM user WHERE id = #{id}
</select>

<!– 动态SQL:根据条件拼接查询条件 –>
<select id=”selectUserByCondition” resultMap=”UserResultMap”>
SELECT id, user_name, age, create_time FROM user
<where>
<if test=”userName != null and userName != ””>
AND user_name LIKE CONCAT(‘%’, #{userName}, ‘%’)
</if>
<if test=”age != null”>
AND age = #{age}
</if>
</where>
</select>

<!– 插入:返回自增主键 –>
<insert id=”insertUser” useGeneratedKeys=”true” keyProperty=”id”>
INSERT INTO user (user_name, age, create_time)
VALUES (#{userName}, #{age}, #{createTime})
</insert>
</mapper>

三、核心特性

1. 参数传递

MyBatis 支持多种参数传递方式:

单个参数:直接通过 #{参数名} 接收(参数名可任意,推荐与接口参数名一致)。

多个参数:

方式 1:使用@Param注解命名参数:

User selectUserByUserNameAndAge(@Param(“userName”) String userName, @Param(“age”) Integer age)

方式 2:封装为实体类 / Map 传递。

数组 / 集合参数:结合<foreach>标签遍历,如批量删除:

<delete id="batchDeleteUser">
    DELETE FROM user WHERE id IN
    <foreach collection="ids" item="id" open="(" separator="," close=")">
        #{id}
    </foreach>
</delete>


2. 动态 SQL

MyBatis 提供丰富的动态 SQL 标签,解决手动拼接 SQL 的痛点:

标签 作用
<if> 条件判断
<where> 自动处理 AND/OR 前缀
<set> 自动处理更新语句的逗号
<foreach> 遍历集合(如 IN 条件)
<choose> 类似 Java 的 switch 语句
<trim> 自定义字符串截取

3. 结果映射

默认映射:字段名与实体属性名完全一致时,无需自定义 resultMap

自定义映射:通过resultMap解决:

字段名与属性名不一致(如数据库 user_name → 实体 userName);

关联查询(一对一 <association>、一对多 <collection>)。

示例(一对多映射):

<resultMap id=”OrderResultMap” type=”com.example.entity.Order”>
<id column=”order_id” property=”orderId”/>
<result column=”order_no” property=”orderNo”/>
<!– 一对多:订单关联多个订单项 –>
<collection property=”orderItems” ofType=”com.example.entity.OrderItem”>
<id column=”item_id” property=”itemId”/>
<result column=”product_name” property=”productName”/>
</collection>
</resultMap>

补:如何去开启全局驼峰命名映射(数据库:user_id → 实体类:userId):

方式 A:在mybatis-config.xml中配置:

<settings>
  <!-- 开启下划线→驼峰自动映射(user_id → userId) -->
  <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>

方式 B:Spring Boot 项目在application.yml中配置:

mybatis:
  configuration:
    map-underscore-to-camel-case: true

4. 缓存机制

MyBatis 缓存(一级 / 二级)的核心目的是提升系统性能、降低数据库压力,本质是 “用内存换速度”—— 把高频访问的数据库查询结果暂存到内存中,后续相同查询直接从内存取数据,无需重复访问数据库。

简单举个例子:

你可以把数据库比作咖啡店的「后厨」,查询请求比作顾客点咖啡,缓存比作吧台的「保温柜」:

没有缓存:

每个顾客点同款拿铁,后厨都要重新磨豆、萃取、冲调(每次查询都走数据库),慢且费资源;

有缓存:

后厨冲好一大壶拿铁放进保温柜,后续点拿铁的顾客直接从保温柜取(查缓存),速度快、后厨压力小。

MyBatis 一级缓存 = 「单个服务员的专属保温柜」(只服务自己接待的顾客);

MyBatis 二级缓存 = 「全店共享的保温柜」(所有服务员都能用来给顾客取咖啡)。

MyBatis 提供两级缓存,默认开启一级缓存,关闭二级缓存:

一级缓存:基于 SqlSession 的本地缓存,同一 SqlSession 中相同 SQL 查询会复用结果(单次会话内重复查询),关闭 SqlSession 后缓存失效。

二级缓存:基于 Mapper 命名空间的全局缓存,多个 SqlSession 可共享(多会话共享静态数据),需手动开启(在 Mapper XML 中添加 <cache/>),且实体类需实现 Serializable

四、MyBatis 与 Spring/Spring Boot 集成

实际开发中,MyBatis 通常与 Spring/Spring Boot 集成,核心依赖:

Spring Boot 配置(application.yml)

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC
    username: root
    password: 123456
mybatis:
  mapper-locations: classpath:mapper/*.xml # Mapper XML 文件位置
  type-aliases-package: com.example.entity # 实体类别名包
  configuration:
    map-underscore-to-camel-case: true # 自动将下划线命名转换为驼峰命名(如user_name → userName)
    cache-enabled: false # 关闭二级缓存

常用注解

@Mapper:标注在 Mapper 接口上,让 Spring 扫描并创建代理对象。

@MapperScan:在启动类上扫描 Mapper 接口包(替代每个接口加@Mapper):

@SpringBootApplication
@MapperScan("com.example.mapper") // 扫描Mapper接口包
public class MyBatisApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyBatisApplication.class, args);
    }
}

五、适用场景

  • 适合需要自定义 SQL、对性能要求高的场景(如电商、金融);
  • 适合数据库结构复杂、需要灵活调整 SQL 的项目;
  • 不适合完全追求 “零 SQL” 的快速开发场景(可选择 JPA/Hibernate)。

六、总结

MyBatis 以 “半自动化 ORM” 为核心,平衡了 SQL 灵活性和开发效率,既保留了开发者对 SQL 的控制权,又简化了 JDBC 操作。它是 Java 后端开发中最常用的持久层框架之一,尤其在互联网项目中广泛应用,掌握其核心组件、动态 SQL、结果映射是使用 MyBatis 的关键。

原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/tech/bigdata/319043.html

(0)
上一篇 1天前
下一篇 2021年7月19日 01:40

发表回复

登录后才能评论