news 2026/8/16 16:10:21

MyBatis 全面解析 Spring Boot 集成实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MyBatis 全面解析 Spring Boot 集成实战

目录

一、MyBatis 核心原理

1. 核心架构

2. 核心特性

二、Spring Boot 集成 MyBatis 实战

1. 环境准备

(1)依赖引入(Maven)

(2)核心配置(application.yml)

2. 代码实现

(1)数据库表设计

(2)实体类

(3)Mapper 接口

(4)Mapper XML 文件(resources/mapper/UserMapper.xml)

(5)Service 层(业务逻辑)

(6)启动类

3. 测试验证

三、MyBatis 高级用法

1. 分页插件(PageHelper)

(1)引入依赖

(2)配置(application.yml)

(3)使用示例

2. 二级缓存

(1)开启全局缓存(application.yml)

(2)在 Mapper XML 中配置缓存

3. 自定义类型处理器

(1)自定义类型处理器

(2)配置类型处理器

(3)使用示例(XML)

四、常见问题与最佳实践

1. 常见问题

2. 最佳实践

五、总结


MyBatis 是一款轻量级、高性能的持久层框架,核心优势是灵活控制 SQL+简化 JDBC 操作,既保留了手写 SQL 的灵活性,又解决了传统 JDBC 繁琐的资源管理、参数设置和结果映射问题。本文将从核心原理、核心特性、Spring Boot 集成实战、高级用法四个维度全面解析 MyBatis。

一、MyBatis 核心原理

1. 核心架构

MyBatis 的核心执行流程可概括为:

plaintext

配置加载 → SqlSessionFactory 创建 → SqlSession 获取 → Mapper 代理生成 → SQL 执行 → 结果映射

关键组件说明:

组件作用
SqlSessionFactory会话工厂(单例),负责创建 SqlSession,通过 SqlSessionFactoryBuilder 构建
SqlSession数据库会话(非线程安全),封装增删改查 API,每次请求 / 事务独立创建
Mapper 接口数据操作接口,MyBatis 通过动态代理生成实现类,接口方法与 SQL 绑定
Mapper XML / 注解存储 SQL 语句、参数映射、结果映射规则
Configuration核心配置类,存储全局配置(数据源、事务、别名、映射器等)
Executor执行器,负责 SQL 执行(SimpleExecutor/BatchExecutor/ReuseExecutor)
StatementHandler处理 Statement(PreparedStatement/Statement),设置参数、执行 SQL
ResultSetHandler将 ResultSet 映射为 Java 对象(结果映射核心)

2. 核心特性

  • 动态 SQL:通过<if>/<where>/<foreach>等标签动态拼接 SQL,适配复杂条件
  • 结果映射:支持一对一、一对多、多对多关联映射,解决字段名与属性名不一致问题
  • 参数解析:支持多种参数类型(基本类型、实体、Map、注解参数),防止 SQL 注入
  • 缓存机制:一级缓存(SqlSession 级别)+ 二级缓存(Mapper 级别),提升查询性能
  • 插件扩展:支持自定义插件(如分页、拦截 SQL),扩展执行流程

二、Spring Boot 集成 MyBatis 实战

1. 环境准备

(1)依赖引入(Maven)

xml

<!-- Spring Boot 父工程 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.2.0</version> <relativePath/> </parent> <dependencies> <!-- MyBatis + Spring Boot 整合启动器 --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>3.0.3</version> </dependency> <!-- MySQL 驱动 --> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency> <!-- Spring Boot 测试 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- Lombok(简化实体类) --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies>
(2)核心配置(application.yml)

yaml

# 数据源配置 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/mybatis_demo?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8 username: root password: 123456 # 连接池配置(默认 HikariCP) hikari: maximum-pool-size: 10 # 最大连接数 minimum-idle: 5 # 最小空闲连接 idle-timeout: 300000 # 空闲连接超时时间 # MyBatis 配置 mybatis: # Mapper XML 文件位置 mapper-locations: classpath:mapper/**/*.xml # 实体类别名包(简化 XML 中 type 配置) type-aliases-package: com.example.mybatis.entity # 全局配置 configuration: map-underscore-to-camel-case: true # 自动下划线转驼峰(如 user_name → userName) cache-enabled: false # 关闭二级缓存(默认开启,按需开启) log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印 SQL 日志 default-statement-timeout: 30 # SQL 执行超时时间

2. 代码实现

(1)数据库表设计

sql

CREATE DATABASE IF NOT EXISTS mybatis_demo; USE mybatis_demo; -- 用户表 CREATE TABLE `user` ( `id` BIGINT AUTO_INCREMENT PRIMARY KEY, `user_name` VARCHAR(50) NOT NULL COMMENT '用户名', `age` INT COMMENT '年龄', `email` VARCHAR(100) COMMENT '邮箱', `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间' ) COMMENT '用户表'; -- 订单表(一对多关联:一个用户多个订单) CREATE TABLE `order` ( `id` BIGINT AUTO_INCREMENT PRIMARY KEY, `order_no` VARCHAR(32) NOT NULL COMMENT '订单号', `user_id` BIGINT NOT NULL COMMENT '用户ID', `amount` DECIMAL(10,2) NOT NULL COMMENT '订单金额', `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ) COMMENT '订单表';
(2)实体类

java

运行

// User.java package com.example.mybatis.entity; import lombok.Data; import java.time.LocalDateTime; import java.util.List; @Data public class User { private Long id; private String userName; // 对应数据库 user_name(下划线转驼峰) private Integer age; private String email; private LocalDateTime createTime; // 一对多关联:用户的订单列表 private List<Order> orderList; } // Order.java package com.example.mybatis.entity; import lombok.Data; import java.math.BigDecimal; import java.time.LocalDateTime; @Data public class Order { private Long id; private String orderNo; private Long userId; private BigDecimal amount; private LocalDateTime createTime; }
(3)Mapper 接口

java

运行

// UserMapper.java package com.example.mybatis.mapper; import com.example.mybatis.entity.User; import org.apache.ibatis.annotations.*; import java.util.List; // 方式1:注解扫描(推荐),也可在启动类加 @MapperScan("com.example.mybatis.mapper") @Mapper public interface UserMapper { /** * 根据ID查询用户(含订单列表) */ User selectById(Long id); /** * 条件查询用户(动态SQL) */ List<User> selectByCondition(@Param("userName") String userName, @Param("age") Integer age); /** * 新增用户(主键回填) */ int insert(User user); /** * 更新用户(动态更新) */ int update(User user); /** * 删除用户 */ int delete(Long id); }
(4)Mapper XML 文件(resources/mapper/UserMapper.xml)

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.mybatis.mapper.UserMapper"> <!-- 基础结果映射:解决字段名与属性名映射 --> <resultMap id="BaseResultMap" type="User"> <id column="id" property="id"/> <!-- 主键映射 --> <result column="user_name" property="userName"/> <result column="age" property="age"/> <result column="email" property="email"/> <result column="create_time" property="createTime"/> </resultMap> <!-- 关联结果映射:用户 + 订单列表(一对多) --> <resultMap id="UserWithOrderResultMap" type="User" extends="BaseResultMap"> <!-- collection 映射一对多关系 --> <collection property="orderList" ofType="Order" column="id" select="com.example.mybatis.mapper.OrderMapper.selectByUserId"/> </resultMap> <!-- 根据ID查询用户(关联订单) --> <select id="selectById" resultMap="UserWithOrderResultMap"> SELECT id, user_name, age, email, create_time FROM user WHERE id = #{id} </select> <!-- 条件查询(动态SQL) --> <select id="selectByCondition" resultMap="BaseResultMap"> SELECT id, user_name, age, email, 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> <!-- 新增用户:useGeneratedKeys 开启主键回填,keyProperty 绑定实体主键 --> <insert id="insert" useGeneratedKeys="true" keyProperty="id"> INSERT INTO user (user_name, age, email) VALUES (#{userName}, #{age}, #{email}) </insert> <!-- 动态更新:set 标签自动处理逗号 --> <update id="update"> UPDATE user <set> <if test="userName != null and userName != ''"> user_name = #{userName}, </if> <if test="age != null"> age = #{age}, </if> <if test="email != null and email != ''"> email = #{email} </if> </set> WHERE id = #{id} </update> <!-- 删除用户 --> <delete id="delete"> DELETE FROM user WHERE id = #{id} </delete> </mapper>

xml

<!-- OrderMapper.xml(resources/mapper/OrderMapper.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.mybatis.mapper.OrderMapper"> <resultMap id="BaseResultMap" type="Order"> <id column="id" property="id"/> <result column="order_no" property="orderNo"/> <result column="user_id" property="userId"/> <result column="amount" property="amount"/> <result column="create_time" property="createTime"/> </resultMap> <select id="selectByUserId" resultMap="BaseResultMap"> SELECT id, order_no, user_id, amount, create_time FROM `order` WHERE user_id = #{userId} </select> </mapper>
(5)Service 层(业务逻辑)

java

运行

// UserService.java package com.example.mybatis.service; import com.example.mybatis.entity.User; import com.example.mybatis.mapper.UserMapper; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; @Service public class UserService { @Resource private UserMapper userMapper; /** * 根据ID查询用户 */ public User selectById(Long id) { return userMapper.selectById(id); } /** * 条件查询 */ public List<User> selectByCondition(String userName, Integer age) { return userMapper.selectByCondition(userName, age); } /** * 新增用户(事务控制) */ @Transactional(rollbackFor = Exception.class) public int insert(User user) { return userMapper.insert(user); } /** * 更新用户 */ @Transactional(rollbackFor = Exception.class) public int update(User user) { return userMapper.update(user); } /** * 删除用户 */ @Transactional(rollbackFor = Exception.class) public int delete(Long id) { return userMapper.delete(id); } }
(6)启动类

java

运行

package com.example.mybatis; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; // 方式2:批量扫描 Mapper 接口(替代每个接口加 @Mapper) // @MapperScan("com.example.mybatis.mapper") @SpringBootApplication public class MybatisDemoApplication { public static void main(String[] args) { SpringApplication.run(MybatisDemoApplication.class, args); } }

3. 测试验证

java

运行

package com.example.mybatis; import com.example.mybatis.entity.User; import com.example.mybatis.service.UserService; import jakarta.annotation.Resource; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import java.util.List; @SpringBootTest public class UserServiceTest { @Resource private UserService userService; @Test public void testInsert() { User user = new User(); user.setUserName("张三"); user.setAge(25); user.setEmail("zhangsan@example.com"); int rows = userService.insert(user); System.out.println("新增行数:" + rows + ",用户ID:" + user.getId()); } @Test public void testSelectById() { User user = userService.selectById(1L); System.out.println("用户信息:" + user); System.out.println("用户订单:" + user.getOrderList()); } @Test public void testSelectByCondition() { List<User> userList = userService.selectByCondition("张", 25); System.out.println("条件查询结果:" + userList); } @Test public void testUpdate() { User user = new User(); user.setId(1L); user.setAge(26); int rows = userService.update(user); System.out.println("更新行数:" + rows); } @Test public void testDelete() { int rows = userService.delete(1L); System.out.println("删除行数:" + rows); } }

三、MyBatis 高级用法

1. 分页插件(PageHelper)

(1)引入依赖

xml

<dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.4.7</version> </dependency>
(2)配置(application.yml)

yaml

pagehelper: helper-dialect: mysql # 数据库方言 reasonable: true # 页码合理化(页码<=0 查第1页,页码>总页数查最后一页) support-methods-arguments: true # 支持通过参数传递分页参数
(3)使用示例

java

运行

@Test public void testPage() { // 第1页,每页10条 PageHelper.startPage(1, 10); List<User> userList = userService.selectByCondition(null, null); // 分页结果封装 PageInfo<User> pageInfo = new PageInfo<>(userList); System.out.println("总条数:" + pageInfo.getTotal()); System.out.println("总页数:" + pageInfo.getPages()); System.out.println("当前页数据:" + pageInfo.getList()); }

2. 二级缓存

(1)开启全局缓存(application.yml)

yaml

mybatis: configuration: cache-enabled: true # 开启二级缓存(默认 true)
(2)在 Mapper XML 中配置缓存

xml

<!-- UserMapper.xml 中添加 --> <cache eviction="LRU" # 缓存淘汰策略(LRU/FIFO/SOFT/WEAK) flushInterval="60000" # 自动刷新时间(毫秒) size="1024" # 缓存最大条目数 readOnly="true"/> # 只读缓存(性能更高)

注意:二级缓存基于 Mapper 级别,仅适用于查询频繁、修改较少的场景;实体类需实现Serializable接口。

3. 自定义类型处理器

解决特殊类型映射(如 JSON 字段、枚举),示例:将List<String>映射为数据库 JSON 字段。

(1)自定义类型处理器

java

运行

package com.example.mybatis.typehandler; import org.apache.ibatis.type.BaseTypeHandler; import org.apache.ibatis.type.JdbcType; import com.alibaba.fastjson2.JSON; import java.sql.*; import java.util.List; public class ListTypeHandler extends BaseTypeHandler<List<String>> { @Override public void setNonNullParameter(PreparedStatement ps, int i, List<String> parameter, JdbcType jdbcType) throws SQLException { ps.setString(i, JSON.toJSONString(parameter)); } @Override public List<String> getNullableResult(ResultSet rs, String columnName) throws SQLException { return JSON.parseArray(rs.getString(columnName), String.class); } @Override public List<String> getNullableResult(ResultSet rs, int columnIndex) throws SQLException { return JSON.parseArray(rs.getString(columnIndex), String.class); } @Override public List<String> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { return JSON.parseArray(cs.getString(columnIndex), String.class); } }
(2)配置类型处理器

yaml

mybatis: type-handlers-package: com.example.mybatis.typehandler # 扫描自定义类型处理器
(3)使用示例(XML)

xml

<resultMap id="BaseResultMap" type="User"> <result column="tags" property="tags" typeHandler="com.example.mybatis.typehandler.ListTypeHandler"/> </resultMap>

四、常见问题与最佳实践

1. 常见问题

问题场景解决方案
字段名与属性名不一致开启map-underscore-to-camel-case或自定义resultMap
SQL 注入风险使用#{}(预编译),避免${}(直接拼接);参数校验
关联查询性能差按需使用association/collection,避免 N+1 查询(可通过fetchType="lazy"懒加载)
分页查询繁琐集成 PageHelper 插件
主键回填失败确保useGeneratedKeys="true"+keyProperty绑定正确,数据库主键自增

2. 最佳实践

  1. SQL 管理:复杂 SQL 写 XML,简单 SQL 用注解(如@Select
  2. 参数传递:多参数使用@Param注解,避免 Map 传递(可读性差)
  3. 结果映射:统一使用resultMap,避免重复配置
  4. 事务控制:在 Service 层加@Transactional,指定rollbackFor = Exception.class
  5. 日志调试:开启 MyBatis SQL 日志,便于定位问题
  6. 性能优化
    • 避免全表扫描,给查询字段加索引
    • 合理使用缓存(一级缓存默认开启,二级缓存按需开启)
    • 批量操作使用foreach+BatchExecutor

五、总结

MyBatis 与 Spring Boot 的整合核心是自动配置+简化开发

  • Spring Boot 自动创建SqlSessionFactorySqlSession,无需手动管理
  • 通过@Mapper@MapperScan扫描 Mapper 接口,动态代理生成实现类
  • 结合 XML / 注解灵活编写 SQL,适配各类业务场景

掌握 MyBatis 的核心是理解映射规则动态 SQL,而 Spring Boot 集成则重点关注配置简化、插件扩展和事务管理。在实际开发中,需结合业务场景选择合适的用法(XML / 注解、缓存策略、分页方式),兼顾灵活性和性能。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/16 0:14:24

Zipkin 深度解析:核心原理、集成实战与最佳实践

目录 一、核心定位与设计理念 1. 核心价值 2. 设计原则 二、核心概念与原理 1. 链路追踪核心术语&#xff08;与 OpenTelemetry 通用&#xff09; 2. 核心工作流程 三、Zipkin 架构组成 架构流程图 四、Spring Boot/Spring Cloud 集成实战 环境准备 步骤 1&#xff1…

作者头像 李华
网站建设 2026/8/14 7:59:14

Windows右键菜单管理终极指南:让你的桌面操作效率提升300%

还在为杂乱的右键菜单烦恼吗&#xff1f;每次安装新软件后&#xff0c;右键菜单就变得更加臃肿&#xff0c;想要的功能找不到&#xff0c;不需要的选项却占满了屏幕。今天我要向你推荐一款完全免费的Windows右键菜单管理工具——ContextMenuManager&#xff0c;它将彻底改变你的…

作者头像 李华
网站建设 2026/8/16 10:55:24

彼得林奇的“长期价值创造“在网络效应企业中的衡量

彼得林奇的"长期价值创造"在网络效应企业中的衡量关键词&#xff1a;彼得林奇、长期价值创造、网络效应企业、价值衡量、企业评估摘要&#xff1a;本文聚焦于彼得林奇所倡导的“长期价值创造”理念在网络效应企业中的衡量问题。首先介绍了研究的背景、目的、预期读者…

作者头像 李华
网站建设 2026/8/16 9:51:37

如何快速实现Unity游戏多语言支持:新手完整指南

在Unity游戏开发与本地化过程中&#xff0c;语言障碍常常成为玩家体验的主要障碍。XUnity.AutoTranslator作为一款专为Unity游戏打造的高效自动翻译工具&#xff0c;提供了完整的本地化解决方案&#xff0c;让游戏语言转换变得简单快捷。本文将带你从零开始&#xff0c;快速掌握…

作者头像 李华