news 2026/4/23 13:04:35

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/4/18 3:27:29

大语言模型推理性能优化:Axolotl缓存加速技术深度解析

大语言模型推理性能优化&#xff1a;Axolotl缓存加速技术深度解析 【免费下载链接】axolotl 项目地址: https://gitcode.com/GitHub_Trending/ax/axolotl 在大规模语言模型应用部署中&#xff0c;重复计算是影响推理效率的主要瓶颈。特别是在客服系统、内容生成平台等高…

作者头像 李华
网站建设 2026/4/23 12:49:17

怎么查看自己Ubuntu剩余空间有多少个G呢?

问题描述&#xff1a;怎么查看自己Ubuntu剩余空间有多少个G呢&#xff1f;问题解答&#xff1a;在 Ubuntu 上查看剩余磁盘空间&#xff08;多少 GB&#xff09;&#xff0c;最常用、也最直观的方法有下面几种 &#x1f447;✅ 方法 1&#xff1a;df -h&#xff08;最推荐&#…

作者头像 李华
网站建设 2026/4/12 5:24:56

LobeChat能否支持永生技术讨论?基因编辑与意识上传伦理辩论

LobeChat能否支持永生技术讨论&#xff1f;基因编辑与意识上传伦理辩论 在人类对“长生不老”的渴望从未停歇的今天&#xff0c;科技正以前所未有的速度逼近这一古老梦想的边界。从CRISPR基因编辑技术精准修改DNA序列&#xff0c;到脑机接口尝试解码神经信号&#xff0c;再到“…

作者头像 李华
网站建设 2026/4/23 11:21:22

LangChain构建智能文档分析系统的7个核心技术模块

在当今信息爆炸的时代&#xff0c;智能文档分析已成为企业和研究机构提升效率的关键技术。LangChain作为领先的AI应用开发框架&#xff0c;为构建高效的文档处理系统提供了完整的解决方案。通过LangChain&#xff0c;我们可以打造能够自动解析、分类和提取关键信息的智能助手&a…

作者头像 李华
网站建设 2026/4/23 9:53:51

安川YASKAWA焊接机器人管材焊接节气

在智能制造与绿色制造的双重浪潮下&#xff0c;焊接行业正积极探索更高效、更环保的生产方式。安川YASKAWA焊接机器人&#xff0c;以其卓越的性能和不断创新的技术&#xff0c;成为了推动焊接行业绿色发展的重要力量。特别是在管材焊接领域&#xff0c;安川焊接机器人通过引入节…

作者头像 李华
网站建设 2026/4/23 9:54:16

10分钟精通Vue可视化打印:vue-plugin-hiprint实战全解析

10分钟精通Vue可视化打印&#xff1a;vue-plugin-hiprint实战全解析 【免费下载链接】vue-plugin-hiprint hiprint for Vue2/Vue3 ⚡打印、打印设计、可视化设计器、报表设计、元素编辑、可视化打印编辑 项目地址: https://gitcode.com/gh_mirrors/vu/vue-plugin-hiprint …

作者头像 李华