从入门到精通详解SpringBoot整合MyBatis的全攻略

 更新时间:2026年05月28日 09:29:03   作者:xiaoyu❅  
在 Java 持久层框架的版图中,MyBatis 无疑占据着举足轻重的地位,本文详细解析了MyBatis核心架构,SpringBoot整合方式,动态SQL与缓存机制并分页的方案,希望对大家有一定的帮助

一、初识 MyBatis:为什么它如此受欢迎?

在 Java 持久层框架的版图中,MyBatis 无疑占据着举足轻重的地位。它是一个优秀的半自动 ORM(对象关系映射)框架,能够将 Java 对象与数据库记录进行映射,支持自定义 SQL、存储过程以及高级映射。相比于 Hibernate 的全自动 ORM,MyBatis 允许开发者直接编写 SQL,在需要精细控制 SQL 执行和复杂查询的场景中,展现出无可比拟的灵活性和性能优势。

简单来说,MyBatis 的核心工作就是 将 SQL 语句与 Java 代码解耦,通过 XML 或注解的配置方式,让你既能享受框架带来的便捷,又能牢牢掌控 SQL 的每一个细节。正因如此,MyBatis 在国内的 Java 开发社区中堪称“半壁江山”,几乎是企业级项目数据访问层的标准配置。

1.1 MyBatis 的核心优势

SQL 与代码解耦:MyBatis 通过 XML 或注解方式将 SQL 语句与 Java 代码分离,开发者可独立维护数据库操作逻辑。DBA 可以直接优化 SQL 而无需修改业务代码,这在需要精细控制 SQL 的遗留系统迁移场景中尤为珍贵。

动态 SQL 灵活构建:MyBatis 提供 <if><choose><foreach> 等标签实现条件拼接,相比于 JPA 的 Criteria API,MyBatis 的动态 SQL 更接近原生 SQL 语法,调试成本可降低 60% 以上。

性能优化空间巨大:一级缓存默认开启,可减少重复查询,缓存命中率可达 35%;延迟加载通过 fetchType="lazy" 实现关联对象按需加载,避免 N+1 查询问题;批处理模式下,1000 条插入操作可从 10 秒压缩至 2 秒。

数据库兼容性强:支持 Oracle、MySQL、PostgreSQL 等 12 种主流数据库,通过 typeAliastypeHandlers 可无缝适配特殊数据类型。

1.2 MyBatis 的局限性

当然,任何框架都不是万能的。当实体类包含 50+ 字段时,XML 映射文件容易变得臃肿(单个实体映射文件超过 800 行时,字段修改导致的维护错误率可能上升 40%)。此外,分页需要手动处理,相比 MyBatis-Plus 的自动分页略显繁琐。

二、MyBatis 核心架构解析

2.1 核心组件

MyBatis 的核心组件如同一个精密的机器,各司其职:

组件作用
SqlSessionFactoryBuilder使用建造者模式,解析配置文件并创建 SqlSessionFactory
SqlSessionFactory工厂类,用于创建 SqlSession,应设计为单例
SqlSession代表一次数据库会话,提供增删改查 API,线程不安全
Configuration存储全局配置信息、映射信息、类型处理器,是 MyBatis 的“大脑”
Executor执行器,负责执行 SQL,维护一级缓存
StatementHandler封装 JDBC Statement 的操作
ParameterHandler负责处理 SQL 参数
ResultSetHandler负责结果集的映射

2.2 一条 SQL 的执行全流程

以执行一次 userMapper.selectUserById(1) 为例,背后的故事是这样的:

1. 初始化
   ├─ SqlSessionFactoryBuilder → 构建 SqlSessionFactory
   └─ SqlSessionFactory → 解析 XML/注解,构建 Configuration

2. 获取 SqlSession
   └─ SqlSessionFactory.openSession() → 创建 DefaultSqlSession

3. Mapper 动态代理
   └─ UserMapper mapper = sqlSession.getMapper(UserMapper.class)(生成 MapperProxy 代理对象)

4. 执行 SQL
   ├─ mapper.selectUserById(1)
   ├─ MapperProxy.invoke() → 根据方法找到 MappedStatement
   └─ SqlSession.selectOne(mappedStatement, params)

5. Executor 执行
   ├─ CachingExecutor (二级缓存) → delegate → SimpleExecutor
   ├─ 创建 StatementHandler
   ├─ ParameterHandler 设置参数
   ├─ JDBC PreparedStatement 执行 SQL
   └─ ResultSetHandler 映射结果

6. 返回结果

整个流程的核心在于:配置 → SqlSessionFactory → SqlSession → Executor → MappedStatement → 数据库

2.3 MappedStatement 的秘密

MappedStatement 是 MyBatis 中一个关键的底层封装对象,它包装了 MyBatis 配置信息及 SQL 映射信息。mapper.xml 文件中的一个 SQL 对应一个 MappedStatement 对象,SQL 的 id 就是 MappedStatement 的 id。在 SQL 执行前,Executor 通过 MappedStatement 将输入的 Java 对象映射至 SQL 中;执行后,再将输出结果映射至 Java 对象中。

三、Spring Boot 整合 MyBatis(实战篇)

3.1 依赖导入

在 Spring Boot 项目中整合 MyBatis,首先需要在 pom.xml 中添加相关依赖:

<!-- MyBatis Spring Boot Starter -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.3.2</version>
</dependency>
<!-- MySQL 驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
<!-- 可选:连接池(HikariCP 已默认包含) -->
<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
</dependency>

小贴士mybatis-spring-boot-starter 会自动引入 mybatismybatis-spring 依赖,我们只需添加这一个 starter 即可。

3.2 配置文件详解(application.yml)

server:
  port: 8080
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mybatis_demo?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
    hikari:
      maximum-pool-size: 10              # 最大连接池数
      minimum-idle: 5                     # 最小空闲连接
      connection-timeout: 30000           # 连接超时时间
      idle-timeout: 600000                # 空闲超时时间
      max-lifetime: 1800000               # 连接最大生命周期
mybatis:
  # 实体类包路径,用于别名自动注册
  type-aliases-package: com.example.demo.entity
  # Mapper XML 文件位置
  mapper-locations: classpath:mapper/*.xml
  configuration:
    # 开启驼峰命名自动映射(例如:user_name → userName)
    map-underscore-to-camel-case: true
    # 开启二级缓存
    cache-enabled: true
    # 开启延迟加载
    lazy-loading-enabled: true
    # 日志输出
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

关键配置解读:

  • map-underscore-to-camel-case: true:这个配置非常实用!开启后,数据库字段 user_name 会自动映射到 Java 实体类的 userName 属性,省去了大量手动映射的烦恼。
  • type-aliases-package:指定实体类包路径后,在 Mapper XML 中就可以直接使用类名(小写形式)而非全限定名。
  • mapper-locations:指定 XML 映射文件的存放位置。

3.3 基于 XML 的开发方式

这是 MyBatis 最经典的开发模式,适合复杂的 SQL 映射场景。

Step 1:创建实体类

package com.example.demo.entity;

import lombok.Data;
import java.util.Date;

@Data
public class User {
    private Long id;
    private String userName;
    private String password;
    private String email;
    private Integer age;
    private Integer status;
    private Date createTime;
    private Date updateTime;
}

Step 2:创建 Mapper 接口

package com.example.demo.mapper;

import com.example.demo.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;

@Mapper
public interface UserMapper {
    User selectUserById(@Param("id") Long id);
    List<User> selectUserList(@Param("userName") String userName);
    int insertUser(User user);
    int updateUser(User user);
    int deleteUserById(@Param("id") Long id);
}

Step 3:编写 Mapper XML 文件

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">
<mapper namespace="com.example.demo.mapper.UserMapper">
    <!-- 结果映射 -->
    <resultMap id="BaseResultMap" type="User">
        <id column="id" property="id" jdbcType="BIGINT"/>
        <result column="user_name" property="userName" jdbcType="VARCHAR"/>
        <result column="password" property="password" jdbcType="VARCHAR"/>
        <result column="email" property="email" jdbcType="VARCHAR"/>
        <result column="age" property="age" jdbcType="INTEGER"/>
        <result column="status" property="status" jdbcType="INTEGER"/>
        <result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
        <result column="update_time" property="updateTime" jdbcType="TIMESTAMP"/>
    </resultMap>
    <!-- 基础字段列表 -->
    <sql id="Base_Column_List">
        id, user_name, password, email, age, status, create_time, update_time
    </sql>
    <!-- 根据 ID 查询用户 -->
    <select id="selectUserById" resultMap="BaseResultMap">
        SELECT <include refid="Base_Column_List"/>
        FROM user
        WHERE id = #{id}
    </select>
    <!-- 条件查询用户列表 -->
    <select id="selectUserList" resultMap="BaseResultMap">
        SELECT <include refid="Base_Column_List"/>
        FROM user
        WHERE 1=1
        <if test="userName != null and userName != ''">
            AND user_name LIKE CONCAT('%', #{userName}, '%')
        </if>
        ORDER BY create_time DESC
    </select>
    <!-- 插入用户 -->
    <insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO user (user_name, password, email, age, status, create_time, update_time)
        VALUES (#{userName}, #{password}, #{email}, #{age}, #{status}, NOW(), NOW())
    </insert>
    <!-- 更新用户 -->
    <update id="updateUser">
        UPDATE user
        <set>
            <if test="userName != null">user_name = #{userName},</if>
            <if test="password != null">password = #{password},</if>
            <if test="email != null">email = #{email},</if>
            <if test="age != null">age = #{age},</if>
            <if test="status != null">status = #{status},</if>
            update_time = NOW()
        </set>
        WHERE id = #{id}
    </update>
    <!-- 删除用户 -->
    <delete id="deleteUserById">
        DELETE FROM user WHERE id = #{id}
    </delete>
</mapper>

Step 4:创建 Service 层

package com.example.demo.service;

import com.example.demo.entity.User;
import java.util.List;

public interface UserService {
    User getUserById(Long id);
    List<User> getUserList(String userName);
    int addUser(User user);
    int modifyUser(User user);
    int removeUser(Long id);
}
package com.example.demo.service.impl;

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

@Service
@Transactional
public class UserServiceImpl implements UserService {
    
    @Autowired
    private UserMapper userMapper;
    
    @Override
    public User getUserById(Long id) {
        return userMapper.selectUserById(id);
    }
    
    @Override
    public List<User> getUserList(String userName) {
        return userMapper.selectUserList(userName);
    }
    
    @Override
    public int addUser(User user) {
        return userMapper.insertUser(user);
    }
    
    @Override
    public int modifyUser(User user) {
        return userMapper.updateUser(user);
    }
    
    @Override
    public int removeUser(Long id) {
        return userMapper.deleteUserById(id);
    }
}

Step 5:Controller 层测试

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.web.bind.annotation.*;
import java.util.List;

@RestController
@RequestMapping("/api/users")
public class UserController {
    
    @Autowired
    private UserService userService;
    
    @GetMapping("/{id}")
    public User getUserById(@PathVariable Long id) {
        return userService.getUserById(id);
    }
    
    @GetMapping("/list")
    public List<User> getUserList(@RequestParam(required = false) String userName) {
        return userService.getUserList(userName);
    }
    
    @PostMapping
    public int addUser(@RequestBody User user) {
        return userService.addUser(user);
    }
    
    @PutMapping
    public int updateUser(@RequestBody User user) {
        return userService.modifyUser(user);
    }
    
    @DeleteMapping("/{id}")
    public int deleteUser(@PathVariable Long id) {
        return userService.removeUser(id);
    }
}

3.4 基于注解的开发方式

对于简单的 CRUD 操作,注解方式更加简洁高效:

package com.example.demo.mapper;

import com.example.demo.entity.User;
import org.apache.ibatis.annotations.*;
import java.util.List;

@Mapper
public interface UserAnnotationMapper {
    
    @Select("SELECT id, user_name, password, email, age, status, create_time, update_time FROM user WHERE id = #{id}")
    @Results(id = "userResultMap", value = {
        @Result(column = "id", property = "id", id = true),
        @Result(column = "user_name", property = "userName"),
        @Result(column = "create_time", property = "createTime"),
        @Result(column = "update_time", property = "updateTime")
    })
    User selectUserById(@Param("id") Long id);
    
    @SelectProvider(type = UserSqlProvider.class, method = "selectUserList")
    @ResultMap("userResultMap")
    List<User> selectUserList(@Param("userName") String userName);
    
    @Insert("INSERT INTO user (user_name, password, email, age, status, create_time, update_time) " +
            "VALUES (#{userName}, #{password}, #{email}, #{age}, #{status}, NOW(), NOW())")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    int insertUser(User user);
    
    @Update("UPDATE user SET user_name = #{userName}, password = #{password}, email = #{email}, " +
            "age = #{age}, status = #{status}, update_time = NOW() WHERE id = #{id}")
    int updateUser(User user);
    
    @Delete("DELETE FROM user WHERE id = #{id}")
    int deleteUserById(@Param("id") Long id);
}

对于复杂查询,可以使用 @SelectProvider 配合 SQL 构建器实现动态 SQL:

package com.example.demo.mapper;

import org.apache.ibatis.jdbc.SQL;

public class UserSqlProvider {
    
    public String selectUserList(String userName) {
        return new SQL() {{
            SELECT("id, user_name, password, email, age, status, create_time, update_time");
            FROM("user");
            if (userName != null && !userName.isEmpty()) {
                WHERE("user_name LIKE CONCAT('%', #{userName}, '%')");
            }
            ORDER_BY("create_time DESC");
        }}.toString();
    }
}

3.5 Mapper 扫描配置

除了在每一个 Mapper 接口上添加 @Mapper 注解,还可以通过 @MapperScan 在配置类中批量扫描:

package com.example.demo.config;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@MapperScan("com.example.demo.mapper")  // 扫描整个 mapper 包
public class MyBatisConfig {
}

四、MyBatis 核心功能深入

4.1 参数传递方式

在 MyBatis 中,Mapper 接口方法支持多种参数传递方式:

方式一:使用 @Param 注解(推荐)

User selectUser(@Param("id") Long id, @Param("status") Integer status);
<select id="selectUser" resultType="User">
    SELECT * FROM user WHERE id = #{id} AND status = #{status}
</select>

方式二:使用对象参数

int insertUser(User user);
<insert id="insertUser">
    INSERT INTO user (user_name, password) VALUES (#{userName}, #{password})
</insert>

方式三:使用 Map 参数

List<User> selectUserByMap(Map<String, Object> params);

4.2 结果集映射

MyBatis 提供了两种结果集映射方式:

简单映射(resultType) :当查询结果的列名与 Java 对象属性名一致(或开启驼峰映射后能匹配)时使用。

复杂映射(resultMap) :支持一对一、一对多等复杂关系映射:

  • 一对一(association) :适用于主表与从表是一对一关系(如:用户和用户详情)
  • 一对多(collection) :适用于主表与从表是一对多关系(如:用户和订单列表)
<!-- 一对一关联映射 -->
<resultMap id="UserWithDetailResultMap" type="User" extends="BaseResultMap">
    <association property="userDetail" javaType="UserDetail" column="id"
                 select="com.example.demo.mapper.UserDetailMapper.selectByUserId"/>
</resultMap>
<!-- 一对多关联映射 -->
<resultMap id="UserWithOrdersResultMap" type="User" extends="BaseResultMap">
    <collection property="orderList" ofType="Order" column="id"
                select="com.example.demo.mapper.OrderMapper.selectByUserId"/>
</resultMap>

性能提示:对于关联映射,建议开启延迟加载(lazyLoadingEnabled=true),避免 N+1 查询问题。

4.3 动态 SQL(核心精华)

动态 SQL 是 MyBatis 最强大的特性之一,允许根据运行时条件动态生成 SQL 语句。

常用动态 SQL 标签详解

标签作用示例
<if>条件判断,满足条件时包含 SQL 片段<if test="name != null">AND name = #{name}</if>
<choose>多条件分支(类似 switch-case)<choose><when test="age != null">AND age = #{age}</when><otherwise>AND age > 18</otherwise></choose>
<where>智能处理 WHERE 子句,自动去除开头 AND/OR<where><if test="name != null">AND name = #{name}</if></where>
<set>智能处理 UPDATE 语句,自动去除结尾逗号<set><if test="name != null">name = #{name},</if></set>
<foreach>遍历集合生成批量操作<foreach item="id" collection="ids" open="(" separator="," close=")">#{id}</foreach>
<trim>自定义字符串修剪<trim prefix="WHERE" prefixOverrides="AND">...</trim>
<bind>创建变量并绑定到上下文<bind name="pattern" value="'%' + keyword + '%'" />

批量插入示例

<insert id="batchInsertUsers">
    INSERT INTO user (user_name, password, email) VALUES
    <foreach collection="list" item="user" separator=",">
        (#{user.userName}, #{user.password}, #{user.email})
    </foreach>
</insert>

批量删除示例

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

动态 SQL 最佳实践:避免嵌套超过 3 层,使用 <where><set> 减少无效字符处理开销,参数合法性在 Java 层校验,简单场景可用 @SelectProvider 替代 XML。

4.4 缓存机制

MyBatis 提供了两级缓存来提升查询性能:

一级缓存(Local Cache)

  • 作用域:SqlSession 级别,默认开启且无法关闭
  • 生命周期:与 SqlSession 一致,执行 INSERT/UPDATE/DELETE 操作或调用 commit()close() 时会清空
  • 适用场景:同一会话内的重复查询,缓存命中率约 5%

二级缓存(Global Cache)

  • 作用域:Mapper 级别(跨 SqlSession 共享),需手动配置开启
  • 存储介质:默认 JVM 内存,可集成 Redis、Ehcache 等
  • 适用场景:多用户并发访问、查询频率高且更新不频繁的数据,缓存命中率可达 90%

启用二级缓存配置

# application.yml
mybatis:
  configuration:
    cache-enabled: true   # 全局开启二级缓存
<!-- Mapper XML 中添加 cache 标签 -->
<mapper namespace="com.example.demo.mapper.UserMapper">
    <cache eviction="LRU" flushInterval="60000" size="512" readOnly="false"/>
</mapper>
// 或者使用注解方式
@CacheNamespace(eviction = LruCache.class, flushInterval = 60000, size = 512)
public interface UserMapper {
}

五、分页方案

5.1 PageHelper 插件(推荐)

PageHelper 是目前最流行的 MyBatis 分页插件,只需在查询前调用 PageHelper.startPage() 即可自动实现物理分页。

添加依赖

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
    <version>2.1.0</version>
</dependency>

使用示例

@Service
public class UserServiceImpl implements UserService {
    
    @Autowired
    private UserMapper userMapper;
    
    public PageInfo<User> getUserListByPage(int pageNum, int pageSize, String userName) {
        // 开启分页(紧跟在后面的第一个查询会被分页)
        PageHelper.startPage(pageNum, pageSize);
        
        // 执行查询
        List<User> userList = userMapper.selectUserList(userName);
        
        // 封装分页结果
        return new PageInfo<>(userList);
    }
}

Controller 调用

@GetMapping("/page")
public PageInfo<User> getUserByPage(@RequestParam(defaultValue = "1") int pageNum,
                                     @RequestParam(defaultValue = "10") int pageSize,
                                     @RequestParam(required = false) String userName) {
    return userService.getUserListByPage(pageNum, pageSize, userName);
}

5.2 分页实现方式对比

MyBatis 主要有五种分页实现方式:

方式类型原理适用场景性能
RowBounds逻辑分页查询全部结果,内存中截取小数据量大数据量易内存溢出
PageHelper物理分页拦截器动态添加 LIMIT 子句通用推荐优秀
SQL 分页物理分页手动编写 LIMIT/OFFSET简单场景较好
数组分页逻辑分页查全表后 subList 截取小数据量
拦截器分页物理分页自定义拦截器统一处理需要统一分页规范时优秀

最佳实践:推荐优先使用 PageHelper 等物理分页方式,避免深分页陷阱。对于超大数据量场景,建议设置 count=false 跳过统计总记录数以提升性能。

六、性能优化指南

6.1 SQL 语句优化

  • 精准查询字段:避免使用 SELECT *,只查询业务所需字段
  • 使用 <sql> 标签:定义可复用字段集合,减少重复书写
  • 批量操作合并:使用 <foreach> 生成批量插入/更新语句,减少数据库交互次数
  • 避免 N+1 查询:合理使用延迟加载或联表查询

6.2 缓存策略优化

  • 一级缓存:默认开启,需配合 @Transactional 注解生效,适用于单事务内重复查询场景
  • 二级缓存:需手动配置开启,适合多用户并发访问场景。注意:不推荐跨 Mapper 共享热点数据,易引发缓存雪崩
  • 分布式缓存:在二级缓存基础上集成 Redis,通过 @Cacheable 注解实现跨服务缓存一致性

6.3 连接池与监控

  • 连接池推荐:HikariCP(Spring Boot 默认)或 Druid,根据业务负载调整 maximum-pool-sizeconnection-timeout 等参数
  • 监控工具:通过 Druid 监控 SQL 执行时间,识别慢查询
  • 日志控制:生产环境关闭 MyBatis 详细日志(log4j.logger.org.mybatis=ERROR),减少 IO 开销

七、多数据源配置

在微服务或复杂业务场景中,多数据源的需求十分常见。推荐使用 dynamic-datasource-spring-boot-starter 开源组件来优雅地实现。

7.1 添加依赖

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
    <version>4.3.0</version>
</dependency>

7.2 配置文件

spring:
  datasource:
    dynamic:
      primary: master                    # 默认数据源
      strict: false                     # 严格模式(匹配不到时抛异常)
      datasource:
        master:
          url: jdbc:mysql://localhost:3306/master_db
          username: root
          password: 123456
          driver-class-name: com.mysql.cj.jdbc.Driver
        slave:
          url: jdbc:mysql://localhost:3306/slave_db
          username: root
          password: 123456
          driver-class-name: com.mysql.cj.jdbc.Driver

7.3 使用 @DS 注解切换数据源

@Service
@DS("master")                    // 类级别指定默认数据源
public class UserServiceImpl implements UserService {
    
    @Autowired
    private UserMapper userMapper;
    
    @Override
    @DS("slave")                 // 方法级别覆盖,从从库读取
    public User getUserById(Long id) {
        return userMapper.selectUserById(id);
    }
    
    @Override
    @DS("master")                // 写入操作使用主库
    public int addUser(User user) {
        return userMapper.insertUser(user);
    }
}

注解优先顺序:方法级别 > 类级别,dynamic-datasource 还支持读写分离、敏感信息加密、分布式事务(基于 Seata)等高级特性。

八、MyBatis-Plus:MyBatis 的超强增强工具

MyBatis-Plus(简称 MP)是 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,极大简化了单表 CRUD 操作。

8.1 核心特性

  • 无侵入:只做增强,不改动 MyBatis 原有逻辑
  • 内置通用 Mapper:提供 BaseMapper 接口,包含常用 CRUD 方法,无需编写 XML
  • 条件构造器:提供 LambdaQueryWrapper,类型安全的条件构造体验
  • 代码生成器:自动生成 Entity、Mapper、Service、Controller 全套代码
  • 内置分页插件:基于物理分页,支持多种数据库

8.2 代码生成器

MyBatis-Plus 的代码生成器 AutoGenerator 可以根据数据库表结构自动生成整套代码,极大提升开发效率。

添加依赖

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.5.3</version>
</dependency>
<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.31</version>
</dependency>

编写代码生成器主类

public class CodeGenerator {
    public static void main(String[] args) {
        FastAutoGenerator.create("jdbc:mysql://localhost:3306/mybatis_demo", "root", "123456")
            .globalConfig(builder -> {
                builder.author("your_name")
                       .outputDir(System.getProperty("user.dir") + "/src/main/java")
                       .commentDate("yyyy/MM/dd");
            })
            .packageConfig(builder -> {
                builder.parent("com.example.demo")
                       .entity("entity")
                       .mapper("mapper")
                       .service("service")
                       .serviceImpl("service.impl")
                       .controller("controller");
            })
            .strategyConfig(builder -> {
                builder.addInclude("user")        // 指定要生成的表名
                       .entityBuilder()
                       .enableLombok()            // 开启 Lombok 支持
                       .idType(IdType.AUTO);      // 主键策略
            })
            .templateEngine(new FreemarkerTemplateEngine())
            .execute();
    }
}

九、常见问题与解决方案

9.1 驼峰命名映射问题

如果开启了 map-underscore-to-camel-case 后仍映射失败,检查:

  1. 实体类属性是否使用了 Lombok(确保有 getter/setter)
  2. 数据库字段名与属性名是否真的匹配(如 userName vs user_name

9.2 SQL 注入问题

始终使用 #{}(预编译参数)而不是 ${}(字符串拼接)。${} 仅用于无法预编译的场景,如动态表名、列名。务必对用户输入进行严格校验。

9.3 分页失效问题

如果 PageHelper 分页不生效,检查:

  1. PageHelper.startPage() 后是否立即执行了查询
  2. 分页参数是否被正确传递
  3. 是否有其他拦截器干扰

9.4 延迟加载不生效

确保在配置文件中开启 lazyLoadingEnabled=true,且关联查询使用 select 属性指定子查询。

十、总结与展望

本文从 MyBatis 的核心概念、架构原理入手,详细讲解了 Spring Boot 整合 MyBatis 的两种主流方式(XML 与注解),深入剖析了动态 SQL、缓存机制、分页方案、性能优化、多数据源配置等进阶内容,最后介绍了 MyBatis-Plus 这个强大的增强工具。

在实际项目开发中,建议根据场景选择合适的组合:

  • 简单项目:Spring Boot + MyBatis(注解方式)+ PageHelper
  • 复杂项目:Spring Boot + MyBatis(XML 方式)+ MyBatis-Plus(仅使用增强功能)
  • 极速开发:Spring Boot + MyBatis-Plus + 代码生成器

MyBatis 以其灵活性和高性能,在国内 Java 社区拥有极其庞大的用户基础。掌握 MyBatis,不仅是一项必备的 Java 开发技能,更是通向高级工程师道路上的一块重要基石。希望本文能帮助你全面掌握 MyBatis 的核心知识,在实际项目中游刃有余!

以上就是从入门到精通详解SpringBoot整合MyBatis的全攻略的详细内容,更多关于SpringBoot整合MyBatis的资料请关注脚本之家其它相关文章!

相关文章

  • Java连接Redis的两种方式

    Java连接Redis的两种方式

    Redis 是一种高性能的键值存储数据库,广泛应用于缓存、消息队列、会话存储等场景,Java 作为一门广泛使用的编程语言,提供了多种方式来连接和操作 Redis,本文将介绍两种常用的 Java 连接 Redis 的方式,需要的朋友可以参考下
    2025-03-03
  • java实现模拟进度计量器

    java实现模拟进度计量器

    这篇文章主要为大家详细介绍了java实现模拟进度计量器,模拟血压计实例,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-07-07
  • java使用JWT的方法

    java使用JWT的方法

    这篇文章主要介绍了java使用JWT的方法,JWT是token的一种,一个JWT字符串包含三个部分分别是Header、Payload和Signature,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下
    2022-06-06
  • 快速掌握SpringBoot应用的启动入口

    快速掌握SpringBoot应用的启动入口

    本篇并不是深究内置服务器的启动过程,而是追溯Springboot启动之前到底做了什么?它是如何与我们经常写的@SpringBootApplication注解注释的main方法类绑定起来的?对SpringBoot启动入口相关知识感兴趣的朋友一起看看吧
    2022-05-05
  • Java String源码分析并介绍Sting 为什么不可变

    Java String源码分析并介绍Sting 为什么不可变

    这篇文章主要介绍了Java String源码分析并介绍Sting 为什么不可变的相关资料,需要的朋友可以参考下
    2017-02-02
  • SpringBoot3集成Redis的方法详解

    SpringBoot3集成Redis的方法详解

    缓存在项目开发中,基本上是必选组件之一,Redis作为一个key-value存储系统,具备极高的数据读写效率,并且支持的数据类型比较丰富,下面我们就来看看SpringBoot3是如何集成Redis的吧
    2023-08-08
  • SpringBoot项目上高并发问题的解决方案

    SpringBoot项目上高并发问题的解决方案

    本章演示在springboot项目中的高并发demo,演示导致的问题,以及单机部署下的解决方案和集群部署下的解决方式以及分布式下的解决方案,文中通过图文结合的方式讲解的非常详细,需要的朋友可以参考下
    2024-06-06
  • 详解Spring Boot最新版优雅停机的方法

    详解Spring Boot最新版优雅停机的方法

    这篇文章主要介绍了Spring Boot最新版优雅停机的相关知识,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-10-10
  • 解决IntellIJ IDEA提示内存不足的图文教程

    解决IntellIJ IDEA提示内存不足的图文教程

    现在越来越多的人投入了 IntellIJ Idea 的怀抱, 它给我们的日常开发带来了诸多便利,但是我们在开发过程中,总是能碰到idea内存不足问题,所以本文给大家介绍了解决IntellIJ IDEA提示内存不足的图文教程,需要的朋友可以参考下
    2025-03-03
  • 邮件收发原理你了解吗? 邮件发送基本过程与概念详解(一)

    邮件收发原理你了解吗? 邮件发送基本过程与概念详解(一)

    你真的了解邮件收发原理吗?这篇文章主要为大家详细介绍了邮件发送基本过程与概念,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-10-10

最新评论