一、核心概念

MyBatis 是一个优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。与 JPA 不同,MyBatis 更强调程序员对 SQL 的完全控制,将 SQL 语句从 Java 代码中分离出来,配置在 XML 文件或使用注解。

1. 核心组件

组件 作用
@Mapper 标记一个接口为 MyBatis 的 Mapper 接口。Spring Boot 会自动扫描并创建其实现。
@Repository 可选,将 Mapper 接口注册为 Spring 的 Bean,便于事务管理。
Mapper 接口 (Interface) 定义数据访问方法。方法名、参数、返回值与 SQL 映射。
SQL 映射文件 (XML) .xml 文件,包含 <select>, <insert>, <update>, <delete> 等标签,定义 SQL 语句和结果映射。文件名通常与 Mapper 接口名相同。
@Select, @Insert, @Update, @Delete 注解方式,直接在 Mapper 接口方法上编写 SQL 语句。适合简单查询。
@Results, @Result 用于定义结果集到 Java 对象的映射关系,常与 @ResultMap@Select 等一起使用。
@Param 当 Mapper 方法有多个参数时,使用 @Param("name") 为参数命名,以便在 SQL 中引用。
SqlSessionFactory MyBatis 的核心工厂,负责创建 SqlSession。Spring Boot 会自动配置。
SqlSession 执行 SQL 命令、获取 Mapper 接口实例、管理事务。通常由 Spring 管理,开发者不直接操作。
MyBatis-Spring-Boot-Starter Spring Boot 官方提供的 Starter,简化了 MyBatis 在 Spring Boot 中的集成。

2. 工作原理

  1. 定义实体类:创建普通的 Java 对象 (POJO)。
  2. 定义 Mapper 接口:创建一个接口,方法代表数据库操作。
  3. 编写 SQL 映射
    • XML 方式:创建一个与接口同名的 .xml 文件,配置 SQL 和结果映射。
    • 注解方式:直接在接口方法上使用 @Select, @Insert 等注解。
  4. 自动扫描:Spring Boot 启动时,扫描 @Mapper 注解的接口。
  5. 动态代理:MyBatis 为每个 Mapper 接口生成一个动态代理实现
  6. 依赖注入:在 Service 中通过 @Autowired 注入 Mapper 接口,调用其方法。
  7. 执行流程:调用 Mapper 方法 -> MyBatis 动态代理拦截 -> 根据方法名/注解找到对应 SQL -> 执行 SQL -> 处理结果集 -> 返回 Java 对象。

二、操作步骤(非常详细)

步骤 1:添加 MyBatis 依赖

pom.xml (Maven) 或 build.gradle (Gradle) 中添加 mybatis-spring-boot-starter

Maven (pom.xml)

<dependencies>
    <!-- MyBatis Spring Boot Starter -->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>3.0.3</version> <!-- 请检查最新版本 -->
    </dependency>

    <!-- 数据库驱动 (以 MySQL 8 为例) -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
</dependencies>

Gradle (build.gradle)

dependencies {
    // MyBatis Spring Boot Starter
    implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.3'

    // Database Driver (MySQL 8)
    runtimeOnly 'mysql:mysql-connector-java'
}

步骤 2:配置数据源和 MyBatis (application.properties)

src/main/resources/application.properties 中配置数据库连接和 MyBatis 相关设置。

# --- 数据源配置 ---
spring.datasource.url=jdbc:mysql://localhost:3306/mybatisdb?useSSL=false&serverTimezone=UTC
spring.datasource.username=myuser
spring.datasource.password=mypassword
# driver-class-name usually not needed

# --- MyBatis 配置 ---
# 指定 Mapper XML 文件的位置 (classpath* 搜索所有 jar 包)
# **XML 方式必须配置!**
mybatis.mapper-locations=classpath*:mapper/*.xml

# 指定实体类所在的包,用于别名注册 (可选,但推荐)
mybatis.type-aliases-package=com.example.demo.entity

# 开启驼峰命名自动映射 (数据库字段名如 user_name -> Java 属性名 userName)
mybatis.configuration.map-underscore-to-camel-case=true

# 开启 MyBatis 日志 (推荐使用 SLF4J)
mybatis.configuration.log-impl=org.apache.ibatis.logging.slf4j.Slf4jImpl

# 其他可选配置
# mybatis.configuration.cache-enabled=true # 是否开启二级缓存
# mybatis.configuration.lazy-loading-enabled=true # 是否开启延迟加载
# mybatis.configuration.aggressive-lazy-loading=false # 是否立即加载所有延迟加载的属性

步骤 3:创建实体类 (POJO)

创建一个普通的 Java 类,属性与数据库表字段对应。

// src/main/java/com/example/demo/entity/User.java
package com.example.demo.entity;

import java.time.LocalDateTime;

// 普通 Java 类,无需 JPA 注解
public class User {

    private Long id;
    private String firstName;
    private String lastName;
    private String email;
    private LocalDateTime createdAt;
    private LocalDateTime updatedAt;

    // 无参构造函数
    public User() {}

    // 全参构造函数 (可选)
    public User(String firstName, String lastName, String email) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.email = email;
    }

    // Getter 和 Setter 方法
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }

    public String getFirstName() { return firstName; }
    public void setFirstName(String firstName) { this.firstName = firstName; }

    public String getLastName() { return lastName; }
    public void setLastName(String lastName) { this.lastName = lastName; }

    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }

    public LocalDateTime getCreatedAt() { return createdAt; }
    public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }

    public LocalDateTime getUpdatedAt() { return updatedAt; }
    public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }

    // toString (推荐)
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", firstName='" + firstName + '\'' +
                ", lastName='" + lastName + '\'' +
                ", email='" + email + '\'' +
                '}';
    }
}

步骤 4:创建 Mapper 接口

创建一个接口,使用 @Mapper 注解。

方式 A:XML 映射文件 (推荐用于复杂 SQL)

// src/main/java/com/example/demo/mapper/UserMapper.java
package com.example.demo.mapper;

import com.example.demo.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Optional;

// 标记为 MyBatis Mapper
@Mapper
// 可选:注册为 Spring Repository Bean
@Repository
public interface UserMapper {

    // 方法名必须与 XML 文件中的 id 一致
    int insertUser(User user);

    // 参数多于一个时,使用 @Param 指定名称
    Optional<User> selectUserById(@Param("id") Long id);

    List<User> selectUsersByLastName(@Param("lastName") String lastName);

    List<User> selectAllUsers();

    int updateUser(User user);

    int deleteUserById(@Param("id") Long id);

    // 自定义查询方法
    List<User> searchUsers(@Param("keyword") String keyword);
}

方式 B:注解方式 (适合简单 SQL)

// src/main/java/com/example/demo/mapper/UserMapper.java
package com.example.demo.mapper;

import com.example.demo.entity.User;
import org.apache.ibatis.annotations.*;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Optional;

@Mapper
@Repository
public interface UserMapper {

    // --- INSERT ---
    @Insert("INSERT INTO users (first_name, last_name, email, created_at, updated_at) " +
            "VALUES (#{firstName}, #{lastName}, #{email}, #{createdAt}, #{updatedAt})")
    @Options(useGeneratedKeys = true, keyProperty = "id") // 获取自增主键
    int insertUser(User user);

    // --- SELECT ---
    @Select("SELECT id, first_name, last_name, email, created_at, updated_at " +
            "FROM users WHERE id = #{id}")
    @Results({
        @Result(property = "id", column = "id"),
        @Result(property = "firstName", column = "first_name"),
        @Result(property = "lastName", column = "last_name"),
        @Result(property = "email", column = "email"),
        @Result(property = "createdAt", column = "created_at"),
        @Result(property = "updatedAt", column = "updated_at")
    })
    Optional<User> selectUserById(@Param("id") Long id);

    @Select("SELECT id, first_name, last_name, email, created_at, updated_at " +
            "FROM users WHERE last_name = #{lastName}")
    List<User> selectUsersByLastName(@Param("lastName") String lastName);

    @Select("SELECT id, first_name, last_name, email, created_at, updated_at FROM users")
    List<User> selectAllUsers();

    // --- UPDATE ---
    @Update("UPDATE users SET first_name = #{firstName}, last_name = #{lastName}, " +
            "email = #{email}, updated_at = #{updatedAt} WHERE id = #{id}")
    int updateUser(User user);

    // --- DELETE ---
    @Delete("DELETE FROM users WHERE id = #{id}")
    int deleteUserById(@Param("id") Long id);
}

步骤 5:创建 SQL 映射文件 (仅 XML 方式)

创建与 Mapper 接口同名的 .xml 文件,放在 src/main/resources/mapper/ 目录下。

<!-- src/main/resources/mapper/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">

<!-- namespace 必须是 Mapper 接口的全限定名 -->
<mapper namespace="com.example.demo.mapper.UserMapper">

  <!-- 通用的 resultMap (可选,用于复杂映射或复用) -->
  <resultMap id="UserResultMap" type="User">
    <id property="id" column="id"/>
    <result property="firstName" column="first_name"/>
    <result property="lastName" column="last_name"/>
    <result property="email" column="email"/>
    <result property="createdAt" column="created_at"/>
    <result property="updatedAt" column="updated_at"/>
  </resultMap>

  <!-- INSERT -->
  <insert id="insertUser" parameterType="User" useGeneratedKeys="true" keyProperty="id">
    INSERT INTO users (
      first_name,
      last_name,
      email,
      created_at,
      updated_at
    ) VALUES (
      #{firstName},
      #{lastName},
      #{email},
      #{createdAt},
      #{updatedAt}
    )
  </insert>

  <!-- SELECT -->
  <!-- resultMap 指向上面定义的 resultMap -->
  <select id="selectUserById" parameterType="long" resultMap="UserResultMap">
    SELECT
      id,
      first_name,
      last_name,
      email,
      created_at,
      updated_at
    FROM users
    WHERE id = #{id}
  </select>

  <select id="selectUsersByLastName" parameterType="string" resultMap="UserResultMap">
    SELECT
      id,
      first_name,
      last_name,
      email,
      created_at,
      updated_at
    FROM users
    WHERE last_name = #{lastName}
  </select>

  <select id="selectAllUsers" resultMap="UserResultMap">
    SELECT
      id,
      first_name,
      last_name,
      email,
      created_at,
      updated_at
    FROM users
  </select>

  <!-- 动态 SQL 示例:searchUsers -->
  <select id="searchUsers" parameterType="string" resultMap="UserResultMap">
    SELECT
      id,
      first_name,
      last_name,
      email,
      created_at,
      updated_at
    FROM users
    <where>
      <if test="keyword != null and keyword != ''">
        (first_name LIKE CONCAT('%', #{keyword}, '%')
        OR last_name LIKE CONCAT('%', #{keyword}, '%')
        OR email LIKE CONCAT('%', #{keyword}, '%'))
      </if>
    </where>
  </select>

  <!-- UPDATE -->
  <update id="updateUser" parameterType="User">
    UPDATE users
    <set>
      <if test="firstName != null">first_name = #{firstName},</if>
      <if test="lastName != null">last_name = #{lastName},</if>
      <if test="email != null">email = #{email},</if>
      updated_at = #{updatedAt}
    </set>
    WHERE id = #{id}
  </update>

  <!-- DELETE -->
  <delete id="deleteUserById" parameterType="long">
    DELETE FROM users WHERE id = #{id}
  </delete>

</mapper>

步骤 6:在 Service 或 Controller 中使用 Mapper

注入 UserMapper 并调用其方法。

// src/main/java/com/example/demo/service/UserService.java
package com.example.demo.service;

import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

@Service
@Transactional // 为数据修改操作添加事务管理
public class UserService {

    @Autowired
    private UserMapper userMapper; // 注入 Mapper

    public User createUser(User user) {
        LocalDateTime now = LocalDateTime.now();
        user.setCreatedAt(now);
        user.setUpdatedAt(now);

        userMapper.insertUser(user); // 执行插入
        // useGeneratedKeys=true 会自动将生成的主键设置回 user 对象
        return user;
    }

    public Optional<User> getUserById(Long id) {
        return userMapper.selectUserById(id);
    }

    public List<User> getAllUsers() {
        return userMapper.selectAllUsers();
    }

    public List<User> getUsersByLastName(String lastName) {
        return userMapper.selectUsersByLastName(lastName);
    }

    public List<User> searchUsers(String keyword) {
        return userMapper.searchUsers(keyword); // 仅 XML 方式有此方法
    }

    public User updateUser(User user) {
        user.setUpdatedAt(LocalDateTime.now());
        userMapper.updateUser(user);
        return user;
    }

    public void deleteUser(Long id) {
        userMapper.deleteUserById(id);
    }
}
// src/main/java/com/example/demo/controller/UserController.java
package com.example.demo.controller;

import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Optional;

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

    @Autowired
    private UserService userService;

    @PostMapping
    public ResponseEntity<User> createUser(@RequestBody User user) {
        User createdUser = userService.createUser(user);
        return ResponseEntity.ok(createdUser);
    }

    @GetMapping("/{id}")
    public ResponseEntity<User> getUser(@PathVariable Long id) {
        Optional<User> userOpt = userService.getUserById(id);
        return userOpt.map(ResponseEntity::ok)
                      .orElseGet(() -> ResponseEntity.notFound().build());
    }

    @GetMapping
    public ResponseEntity<List<User>> getAllUsers() {
        List<User> users = userService.getAllUsers();
        return ResponseEntity.ok(users);
    }

    @GetMapping("/search")
    public ResponseEntity<List<User>> searchUsers(@RequestParam String keyword) {
        List<User> users = userService.searchUsers(keyword);
        return ResponseEntity.ok(users);
    }

    @PutMapping("/{id}")
    public ResponseEntity<User> updateUser(@PathVariable Long id, @RequestBody User user) {
        // 确保 ID 一致
        user.setId(id);
        User updatedUser = userService.updateUser(user);
        return ResponseEntity.ok(updatedUser);
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
        return ResponseEntity.noContent().build();
    }
}

步骤 7:启动应用并测试

  1. 启动 Spring Boot 应用。
  2. 确保数据库 mybatisdb 存在,并创建了 users 表(可手动创建或使用其他工具)。
    CREATE TABLE users (
      id BIGINT AUTO_INCREMENT PRIMARY KEY,
      first_name VARCHAR(50) NOT NULL,
      last_name VARCHAR(50) NOT NULL,
      email VARCHAR(100) UNIQUE NOT NULL,
      created_at DATETIME NOT NULL,
      updated_at DATETIME NOT NULL
    );
    
  3. 使用 Postman, curl 或浏览器测试 API 端点。

三、常见错误与解决方案

错误 原因 解决方案
Invalid bound statement (not found): com.example.demo.mapper.UserMapper.selectUserById Mapper XML 文件未被正确加载或 namespace/id 不匹配 1. 检查 application.propertiesmybatis.mapper-locations 路径是否正确(如 classpath*:mapper/*.xml)。2. 确认 XML 文件在 src/main/resources 下。3. 检查 XML 中的 namespace 是否是 Mapper 接口的全限定名。4. 检查 <select> 等标签的 id 是否与接口方法名完全一致。
BindingException: Parameter 'xxx' not found Mapper 方法参数未用 @Param 注解,但在 SQL 中引用了 当 Mapper 方法有多个参数时,必须使用 @Param("name") 为每个参数命名。单个参数(如 POJO)通常不需要。
org.apache.ibatis.reflection.ReflectionException: Could not set property 'xxx' of 'class com.example.demo.entity.User' 实体类缺少 setter 方法或属性名不匹配 1. 确保实体类为需要映射的字段提供了 public 的 setter 方法。2. 检查数据库列名与 Java 属性名是否匹配(考虑驼峰命名转换 map-underscore-to-camel-case)。3. 在 resultMap@Results 中明确指定 propertycolumn 的映射。
org.apache.ibatis.binding.BindingException: Invalid return type for method SQL 查询返回的列数/类型与返回的 Java 对象不匹配 1. 确保 SELECT 语句返回了所有需要的列。2. 检查 resultMap@Results 定义是否正确。3. 对于 Optional<T>,确保查询可能返回 null(如 SELECT ... WHERE id = ?)。
java.sql.SQLIntegrityConstraintViolationException 违反了数据库约束 (唯一键、非空等) 检查插入/更新的数据是否符合数据库表的约束。在业务逻辑中提前验证(如检查邮箱是否已存在)。
NoSuchBeanDefinitionException: No qualifying bean of type 'YourMapper' Mapper 接口未被 Spring 扫描到 1. 确保 Mapper 接口上有 @Mapper 注解。2. 确保主应用类(@SpringBootApplication)的包能扫描到 Mapper 接口(通常在子包下)。3. 或者,在主应用类上使用 @MapperScan("com.example.demo.mapper") 注解指定扫描包。

四、注意事项

  1. @Mapper vs @MapperScan
    • @Mapper:需要在每个 Mapper 接口上添加。
    • @MapperScan:在主应用类或配置类上使用一次,指定 Mapper 接口所在的包,Spring Boot 会自动扫描该包下所有接口。
    @SpringBootApplication
    @MapperScan("com.example.demo.mapper") // 推荐方式
    public class Application { ... }
    
  2. @Param 的使用当方法有多个参数时,必须使用 @Param。单个参数(如 POJO 或基本类型)通常可以省略,但显式使用 @Param 更清晰。
  3. SQL 注入风险:MyBatis 使用 #{} 进行参数占位,能有效防止 SQL 注入。避免使用 ${},除非你完全信任输入且需要动态表名/列名。
  4. useGeneratedKeys & keyProperty:对于自增主键,<insert> 标签或 @Insert 注解需要设置 useGeneratedKeys="true"keyProperty="id"id 是实体类中主键属性名),才能将生成的主键值回填到实体对象。
  5. resultMap vs resultType
    • resultType:当数据库列名与 Java 属性名能自动匹配(如开启驼峰转换)时使用,更简洁。
    • resultMap:当需要复杂映射(如关联查询、列名与属性名不一致、类型转换)时使用,更灵活。
  6. @Transactional:对数据修改操作(insert, update, delete强烈建议使用 @Transactional 注解,确保操作的原子性。
  7. Optional<T>:MyBatis 支持返回 Optional<T>,当查询结果为空时返回 Optional.empty()。注意,List<T> 永远不会是 null,空结果返回空 List

五、使用技巧

  1. 动态 SQL:MyBatis 的强大之处在于动态 SQL。熟练使用 <if>, <choose>, <when>, <otherwise>, <where>, <set>, <foreach> 等标签构建灵活的查询。
    • <where>:自动处理 WHERE 关键字和多余的 AND/OR
    • <set>:自动处理 SET 关键字和多余的逗号。
    • <foreach>:用于 IN 子句或批量操作。
  2. <sql> 片段:抽取可重用的 SQL 片段。
    <sql id="baseColumns">
      id, first_name, last_name, email, created_at, updated_at
    </sql>
    <select id="selectAllUsers" resultMap="UserResultMap">
      SELECT <include refid="baseColumns"/> FROM users
    </select>
    
  3. <association><collection>:处理一对一、一对多关联映射。
  4. @Options 注解:用于 @Insert, @Update 等,设置 useGeneratedKeys, keyProperty, timeout 等。
  5. @ResultMap:在方法上引用已定义的 resultMap
    @Select("SELECT * FROM users")
    @ResultMap("UserResultMap")
    List<User> selectAllUsers();
    
  6. @SelectProvider, @InsertProvider:使用 Java 代码动态生成 SQL 语句。
  7. @UpdateProvider:配合 @ParamMap 实现更灵活的更新逻辑。
  8. RowBounds:用于分页(逻辑分页,不推荐用于大数据量)。
    List<User> selectAllUsers(RowBounds rowBounds);
    
  9. @Flush:强制刷新所有待执行的语句到数据库。

六、最佳实践

  1. 选择 XML 还是注解
    • XML 方式推荐。SQL 与代码分离,便于维护、格式化、版本控制,支持复杂的动态 SQL 和 resultMap
    • 注解方式:适合非常简单的 CRUD 操作。SQL 写在 Java 代码中,不利于复杂 SQL 的管理和阅读。
  2. 使用 @MapperScan:避免在每个 Mapper 接口上写 @Mapper
  3. 分层架构:Controller -> Service -> Mapper。Mapper 只负责数据访问,Service 负责业务逻辑和事务。
  4. 事务管理:在 Service 层 使用 @Transactional
  5. 使用 #{}:始终使用 #{parameter} 进行参数绑定,防止 SQL 注入。${} 仅在极少数需要动态 SQL 片段时使用,并确保输入安全。
  6. 合理使用动态 SQL:利用 MyBatis 的动态标签构建安全、高效的查询。
  7. DTO 模式:在 Controller 层和前端之间使用 DTO,避免直接暴露实体类。
  8. 日志配置:开启 MyBatis 日志(log-impl=SLF4J),便于调试 SQL 语句和参数。
  9. map-underscore-to-camel-case:开启驼峰命名转换,减少 resultMap 的定义。
  10. 主键回填:对于自增主键,务必配置 useGeneratedKeyskeyProperty

七、性能优化

  1. 避免 N+1 查询:虽然 MyBatis 默认是 EAGER,但复杂关联仍需注意。使用 <association><collection>select 属性(延迟加载)或 JOIN 查询一次性获取数据。谨慎使用延迟加载。
  2. 使用二级缓存 (2nd Level Cache):MyBatis 支持二级缓存(基于 namespace)。在 Mapper XML 中使用 <cache/> 标签开启。注意缓存一致性问题,在高并发写场景下可能不适用。
    <mapper namespace="com.example.demo.mapper.UserMapper">
      <cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/>
      ...
    </mapper>
    
  3. 合理使用 fetchType:在 <association><collection> 中设置 fetchType="lazy" 实现延迟加载。
  4. 批量操作
    • 批量插入:使用 <foreach> 构建 INSERT INTO ... VALUES (...), (...), (...) 语句。
      <insert id="batchInsertUsers">
        INSERT INTO users (first_name, last_name, email, created_at, updated_at)
        VALUES
        <foreach collection="users" item="user" separator=",">
          (#{user.firstName}, #{user.lastName}, #{user.email}, #{user.createdAt}, #{user.updatedAt})
        </foreach>
      </insert>
      
    • 批量更新/删除:类似地使用 <foreach>
  5. 连接池优化:确保底层数据源(如 HikariCP)配置合理(最大连接数、最小空闲连接、连接超时等)。
  6. SQL 优化:编写高效的 SQL 语句,为查询条件字段添加数据库索引。
  7. 减少查询字段:只 SELECT 需要的字段,避免 SELECT *
  8. 分页:对于大数据量查询,必须使用物理分页。可以使用 MyBatis-Plus 的分页插件,或在 SQL 中使用 LIMIT/ROWNUM/OFFSET FETCH 等数据库特定语法。

总结

MyBatis 提供了对 SQL 的完全控制,适合需要编写复杂、高性能 SQL 的场景。

快速掌握路径

  1. 添加依赖mybatis-spring-boot-starter + 数据库驱动。
  2. 配置application.properties 中设置数据源和 mybatis.mapper-locations, mybatis.type-aliases-package, mybatis.configuration.map-underscore-to-camel-case
  3. 创建实体:普通的 POJO。
  4. 创建 Mapper 接口:使用 @Mapper@MapperScan
  5. 编写 SQL
    • 推荐 XML:创建 .xml 文件,配置 SQL 和 resultMap
    • 简单 SQL:使用 @Select, @Insert 等注解。
  6. 注入 Mapper:在 Service 中 @Autowired 并调用方法。
  7. 添加 @Transactional:在 Service 的修改方法上。
  8. 测试:通过 API 验证功能。

遵循最佳实践,特别是使用 XML 方式、合理使用动态 SQL、开启驼峰转换、注意事务和性能,你就能高效地使用 MyBatis 进行数据访问。