﻿---
title: Apache MyBatis
date: 2024-07-20
excerpt: MyBatis，黑马程序员Java Web
tags: [Java, MyBatis, Apache]
thumbnail: https://assets.vluv.space/cover/Dev/Java/mybatis.webp
cover: https://assets.vluv.space/cover/Dev/Java/mybatis.webp
updated: 2026-06-06 22:12:32
---

<script type="module" src="/js/components/tab.js"></script>

## Introduction

- MyBatis 是一款 持久层框架（Persistence Framework），它简化了 Java 程序与数据库之间的交互。与传统的 JDBC（Java Database Connectivity，Java 数据库连接）相比，MyBatis 通过 XML 或注解方式来配置和映射 SQL 语句，大大减少了冗余的代码编写工作。
- MyBatis 本是 Apache 的一个开源项目 iBatis, 2010 年这个项目由 apache 迁移到了 google code，并且改名为 MyBatis 。2013 年 11 月迁移到 GitHub。

> **JDBC（Java DataBase Connectivity）**
>
> JDBC 是 Java 中用于数据库连接的 API，由 Sun Microsystems（现在是 Oracle Corporation 的一部分）在 1997 年发布。JDBC 提供了一种基准，使得 Java 程序可以与多种关系数据库进行交互。JDBC 提供了一组接口和类，使得开发人员可以发送 SQL 语句并处理结果。JDBC 驱动程序是实现了 JDBC 接口的特定 DBMS 的 Java 类库。Java 程序通过 JDBC 驱动程序与 DBMS 进行通信。
>
> **持久化框架 Persistence Framework**
>
> In computing a **persistence framework** is middleware that assists in the storage and retrieval of information between applications and databases, especially relational databases. It acts as a layer of abstraction for persisted data, bridging conceptual and technical differences between storage and utilisation.
> Many persistence frameworks are also **object-relational mapping** (ORM) tools (e.g. Hibernate, MyBatis SQL Maps, Apache Cayenne, Entity Framework, Slick, and Java Ultra-Lite Persistence). Such frameworks map the objects in the application domain to data that needs to be persisted in a database. The mappings can be defined using either XML files or metadata annotations.
>
> 对象关系映射（英语：Object Relational Mapping，简称 ORM，或 O/RM，或 O/R mapping），是一种程序设计技术，用于实现面向对象编程语言里不同类型系统的资料之间的转换。面向对象是从软件工程基本原则（如耦合、聚合、封装）的基础上发展起来的，而关系数据库则是从数学理论发展而来的，两套理论存在显著的区别。为了解决这个不匹配的现象，对象关系映射技术应运而生。
>
> **和其他持久化层技术对比**
>
> - JDBC
>   - SQL 夹杂在 Java 代码中耦合度高，导致硬编码内伤；
>   - 维护不易且实际开发需求中 SQL 有变化，频繁修改的情况多见；
>   - 代码冗长，开发效率低；
> - Hibernate 和 JPA
>   - 操作简便，开发效率高；
>   - 程序中的长难复杂 SQL 需要绕过框架；
>   - 内部自动生成的 SQL，不容易做特殊优化；
>   - 基于全映射的全自动框架，大量字段的 POJO 进行部分映射时比较困难；
>   - 反射操作太多，导致数据库性能下降；
> - MyBatis
>   - 轻量级，性能出色；
>   - SQL 和 Java 编码分开，功能边界清晰。Java 代码专注业务、SQL 语句专注数据；
>   - 开发效率稍逊于 HIbernate，但是完全能够接收；
>
> 开发效率：`Hibernate > Mybatis > JDBC`；
> 运行效率：`JDBC > Mybatis > Hibernate`；
>
> **为什么说 MyBatis 是半自动 ORM 映射工具？它与全自动的区别在哪里？**
>
> Hibernate 属于全自动 ORM 映射工具，使用 Hibernate 查询关联对象或者关联集合对象时，可以根据对象关系模型直接获取，所以它是全自动的。而 MyBatis 提供了一种灵活的、半自动化的方式来处理数据库操作。不同于全自动的 ORM 框架，MyBatis 更强调 SQL 控制权，开发者可以自行编写 SQL 语句，从而获得更好的性能和灵活性。

MyBatis 的核心优势在于以下几个方面：

- SQL 控制权（SQL Control）：你可以完全掌握 SQL 语句的编写和执行，避免了 ORM 框架的复杂性，特别是当你需要优化查询时。
- 动态 SQL 支持（Dynamic SQL Support）：MyBatis 提供了非常强大的动态 SQL 支持，开发者可以根据业务逻辑灵活生成不同的 SQL 语句，避免了拼接 SQL 字符串的烦恼。
- 轻量级（Lightweight）：MyBatis 轻量且易于集成，不会像一些复杂的 ORM 框架那样引入过多的依赖。
- 简化的映射关系（Simplified Mapping）：通过 XML 配置或注解方式，可以轻松地将数据库表的字段与 Java 对象的属性进行映射（Mapping）。

### MyBatis Core Concepts

- `SqlSessionFactory`是 MyBatis 核心的入口点，每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。它是通过读取配置文件（Configuration File）来创建的。通过 SqlSessionFactory，可以获取到 SqlSession，并进行数据库操作。
- `SqlSession`类似于 JDBC 的 `Statement` 对象，提供与数据库交互的方法。通过 SqlSession 可以执行增删改查操作、提交事务（Transaction）、关闭连接等，每个对话之间相互隔离
- `Mapper Interface` 是 MyBatis 提供的另一种便捷的方式来操作数据库表。可以通过定义接口来对应数据库表中的操作，每个方法映射到一条 SQL 语句。例如，一个 UserMapper 接口可能会有方法 `getUserById()` 对应 `SELECT * FROM user WHERE id = ?` 的 SQL 语句。
- `Dynamic SQL` 是 MyBatis 中的一个强大功能，允许你在 SQL 中使用条件语句（如 `if、choose、where`）以及循环（`foreach`）等控制结构。动态 SQL 提高了代码的灵活性，特别是在应对复杂查询条件时，它可以根据条件动态生成 SQL 语句。
- `Result Mapping`，结果集映射，指将查询结果中的数据库字段映射到 Java 对象的属性中，可以通过 XML 配置或者注解来定义这种映射关系。

## CRUD Demo

假设我们有一个 `User` 表，包含 id、name、age 等属性。

```sql
CREATE TABLE user (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50),
    age INT
);
```

<x-tabs>

<x-tab title="项目结构" active>

在这个项目结构中，我们使用了 Spring Boot 的典型层次化结构来组织 MyBatis 的 CRUD 操作：

`Model Layer` ：定义 User 实体类。
`Mapper Layer` ：通过 UserMapper 接口定义数据库操作，并用 UserMapper.xml 文件来配置 SQL 语句。
`Service Layer` ：通过 UserService 类封装业务逻辑。
`Controller Layer` ：通过 UserController 接收 HTTP 请求并调用 UserService 执行相应的数据库操作。

```nu
src/
 └── main/
     ├── java/
     │    └── com/
     │        └── example/
     │            └── mybatisdemo/
     │                 ├── controller/
     │                 │    └── UserController.java
     │                 ├── mapper/
     │                 │    └── UserMapper.java
     │                 ├── model/
     │                 │    └── User.java
     │                 └── service/
     │                      └── UserService.java
     └── resources/
          ├── application.yml
          └── mapper/
               └── UserMapper.xml
```

```yml
# application.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mybatis_demo
    username: root
    password: root_password
    driver-class-name: com.mysql.cj.jdbc.Driver

mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.example.mybatisdemo.model
```

</x-tab>

<x-tab title="Model">

```java
package com.example.mybatisdemo.model;

public class User {
    private int id;
    private String name;
    private int age;

    // Getters and Setters
    public int getId() { return id; }
    public void setId(int id) { this.id = id; }

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
}
```

</x-tab>

<x-tab title="Service">

```java
package com.example.mybatisdemo.service;

import com.example.mybatisdemo.mapper.UserMapper;
import com.example.mybatisdemo.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    public int createUser(User user) {
        return userMapper.insertUser(user);
    }

    public User getUserById(int id) {
        return userMapper.getUserById(id);
    }

    public int updateUser(User user) {
        return userMapper.updateUser(user);
    }

    public int deleteUser(int id) {
        return userMapper.deleteUser(id);
    }
}
```

</x-tab>

<x-tab title="Mapper">

```java
package com.example.mybatisdemo.mapper;

import com.example.mybatisdemo.model.User;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserMapper {

    // 插入一条用户数据
    int insertUser(User user);

    // 根据用户 ID 查询
    // 在`xml`文件中，编写对应的SQL语句，例如
    // <select id = "getUserById" resultType = "User">
    //     select * from user where id = #{id}
    // </select>
    User getUserById(int id);

    // 更新用户信息
    int updateUser(User user);

    // 根据用户 ID 删除
    int deleteUser(int id);
}
```

</x-tab>

<x-tab title="Controller">

```java
package com.example.mybatisdemo.controller;

import com.example.mybatisdemo.model.User;
import com.example.mybatisdemo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/users")
public class UserController {

    @Autowired
    private UserService userService;

    // 创建用户
    @PostMapping
    public String createUser(@RequestBody User user) {
        userService.createUser(user);
        return "用户创建成功";
    }

    // 根据 ID 查询用户
    @GetMapping("/{id}")
    public User getUserById(@PathVariable int id) {
        return userService.getUserById(id);
    }

    // 更新用户
    @PutMapping("/{id}")
    public String updateUser(@PathVariable int id, @RequestBody User user) {
        user.setId(id);
        userService.updateUser(user);
        return "用户更新成功";
    }

    // 删除用户
    @DeleteMapping("/{id}")
    public String deleteUser(@PathVariable int id) {
        userService.deleteUser(id);
        return "用户删除成功";
    }
}
```

</x-tab>

</x-tabs>

## More

[MyBatis 常见面试题总结](https://javaguide.cn/system-design/framework/mybatis/mybatis-interview.html)
[对象关系映射](https://zh.wikipedia.org/wiki/%E5%AF%B9%E8%B1%A1%E5%85%B3%E7%B3%BB%E6%98%A0%E5%B0%84)
