在现代 Java 开发中,持久层框架扮演着至关重要的角色。MyBatis 作为一款轻量级的半自动化 ORM(对象关系映射)框架,凭借其灵活性和高性能,广泛应用于企业级项目开发中。结合 Spring Boot 的自动配置能力,可以快速搭建高效的数据访问层。
本文将系统性地讲解 MyBatis + Spring Boot 的整合流程、动态 SQL 使用技巧、关联查询处理、缓存机制、AOP 与事务管理 等核心知识点,帮助你构建完整的知识体系。
一、什么是 MyBatis?
MyBatis 是一个支持自定义 SQL、存储过程和高级映射的持久层框架。它将接口方法与 SQL 语句进行绑定,通过 XML 或注解的方式实现数据库操作。
- 半自动化 ORM:不像 Hibernate 完全屏蔽 SQL,MyBatis 允许开发者精细控制 SQL。
- 轻量级:不依赖复杂容器,易于集成。
- 灵活性高:适合复杂查询、多表联查等场景。
二、Spring Boot 整合 MyBatis 步骤
✅ 步骤一:添加依赖
在 pom.xml
中引入 mybatis-spring-boot-starter
:
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
提示:Spring Boot 会自动配置
SqlSessionFactory
和SqlSessionTemplate
。
✅ 步骤二:配置文件设置(application.yml)
spring:
datasource:
url: jdbc:mysql://localhost:3306/tms2024?useSSL=false&serverTimezone=UTC
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.situ.tms2024.entity
configuration:
map-underscore-to-camel-case: true # 开启驼峰命名转换
✅ 步骤三:编写 Mapper 接口
使用 @Mapper
注解标识接口:
@Mapper
public interface StudentMapper {
List<Student> findAll();
Student findById(Long id);
int insert(Student student);
}
💡 也可在启动类上加
@MapperScan("com.situ.tms2024.dao")
批量扫描。
✅ 步骤四:编写动态 SQL 文件(Mapper XML)
创建 StudentMapper.xml
,路径需与 mapper-locations
一致:
<?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.situ.tms2024.dao.StudentMapper">
<select id="findAll" resultType="Student">
SELECT * FROM t_student
</select>
<select id="findById" resultType="Student">
SELECT * FROM t_student WHERE id = #{id}
</select>
<insert id="insert" parameterType="Student" useGeneratedKeys="true" keyProperty="id">
INSERT INTO t_student (name, sex, birthday) VALUES (#{name}, #{sex}, #{birthday})
</insert>
</mapper>
⚠️ 注意:
id
必须唯一,且与接口方法名一致。
✅ 步骤五:推荐安装 MyBatis-X 插件(IDEA)
MyBatis-X 是一款 IntelliJ IDEA 插件,可实现:
- 接口与 XML 跳转
- 自动生成 CRUD 方法
- 快速生成 resultMap
安装方式:IDEA → Plugins → 搜索 "MyBatisX" → 安装重启即可。
三、动态 SQL 与参数传递
MyBatis 使用 OGNL(Object-Graph Navigation Language)表达式 解析参数,通过反射机制获取对象属性值。
1. 单个参数(JavaBean 或 Map)
可以直接使用属性名访问:
<select id="findByAge" resultType="Student">
SELECT * FROM t_student WHERE age = #{age}
</select>
调用时传入 Student
对象或 Map<String, Object>
。
2. 多个参数(必须命名)
MyBatis 默认将多个参数封装为 param1
, param2
... 或 arg0
, arg1
...
推荐使用 @Param
显式命名:
List<Student> findByNameAndAge(@Param("name") String name, @Param("age") Integer age);
<select id="findByNameAndAge" resultType="Student">
SELECT * FROM t_student
WHERE name LIKE CONCAT('%', #{name}, '%')
AND age >= #{age}
</select>
❗ 若使用了
@Param("xxx")
,则 XML 中必须用#{xxx}
引用。
3. 模型查询:模糊匹配
方式一:使用 <bind>
标签(推荐)
<select id="findByNameLike" parameterType="string" resultType="Student">
<bind name="nameLike" value="'%' + name + '%'"/>
SELECT * FROM t_student WHERE name LIKE #{nameLike}
</select>
✅ 安全,防止 SQL 注入。
方式二:使用 ${}
(慎用)
<select id="findByNameLike">
SELECT * FROM t_student WHERE name LIKE '%${name}%'
</select>
⚠️
${}
是字符串拼接,存在 SQL 注入风险,仅用于动态表名、排序字段等特殊场景。
四、结果映射与关联查询
1. 手动映射(resultMap)
当字段名与属性名不一致时,需自定义 resultMap
:
<resultMap id="StudentResultMap" type="Student">
<id property="id" column="id"/>
<result property="stuId" column="stu_id"/>
<result property="py" column="pinyin"/>
<result property="classEntity.id" column="class_id"/>
</resultMap>
然后在查询中引用:
<select id="findAll" resultMap="StudentResultMap">
SELECT id, stu_id, name, pinyin, class_id FROM t_student
</select>
2. 一对一关联
<resultMap id="StudentWithClass" type="Student">
<association property="classEntity" javaType="Class">
<id property="id" column="class_id"/>
<result property="className" column="class_name"/>
</association>
</resultMap>
3. 一对多关联(班级与学生)
<resultMap id="ClassWithStudents" type="Class">
<id property="id" column="id"/>
<result property="className" column="class_name"/>
<collection property="students" ofType="Student">
<id property="id" column="sid"/>
<result property="name" column="sname"/>
</collection>
</resultMap>
<select id="findClassWithStudents" resultMap="ClassWithStudents">
SELECT c.id, c.class_name, s.id as sid, s.name as sname
FROM t_class c
LEFT JOIN t_student s ON c.id = s.class_id
WHERE c.id = #{id}
</select>
或使用 嵌套查询 解决 N+1 问题:
<collection
property="students"
column="id"
select="com.situ.tms2024.dao.StudentMapper.findByClassId"/>
五、性能优化:缓存机制
1. 一级缓存(默认开启)
- 作用域:同一个
SqlSession
内。 - 特点:同一次会话中相同 SQL 只执行一次,结果缓存。
- 失效条件:
insert/update/delete
操作后、手动清空、会话关闭。
2. 二级缓存(应用级缓存)
启用步骤:
-
开启全局缓存
mybatis:
configuration:
cache-enabled: true -
实体类实现
Serializable
public class Student implements Serializable { ... }
-
在 Mapper XML 中声明缓存
<cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/>
eviction
: 回收策略(LRU/FIFO/SOFT/WEAK)flushInterval
: 刷新间隔(毫秒)size
: 最多缓存对象数readOnly
: 是否只读(提高性能)
-
在 SQL 标签中控制缓存行为
<select id="findAll" useCache="true">...</select>
<insert id="insert" flushCache="true">...</insert>
✅ 二级缓存跨
SqlSession
生效,提升并发性能。
3. 延迟加载(Lazy Loading)
mybatis:
configuration:
lazy-loading-enabled: true
aggressive-lazy-loading: false
aggressive-lazy-loading=false
:仅加载被调用的延迟属性。- 每次访问延迟属性会发起新会话,一级缓存失效。
六、Spring AOP:面向切面编程
什么是 AOP?
传统编程是纵向执行流程,而 AOP 是横向切入逻辑,如日志记录、权限校验、事务管理等。
核心概念:
- 切面(Aspect):横切关注点的模块化(如日志切面)。
- 连接点(Join Point):程序执行过程中的某个点(如方法调用)。
- 通知(Advice):在连接点执行的动作(前置、后置、环绕等)。
- 切入点(Pointcut):匹配连接点的表达式。
实现原理:动态代理
类型 | 说明 |
---|---|
JDK 动态代理 | 基于接口,目标类必须实现接口 |
CGLIB 动态代理 | 基于继承,目标类不能是 final |
Spring 默认优先使用 JDK 动态代理,若无接口则使用 CGLIB。
七、事务管理(基于 Spring AOP)
1. 事务的 ACID 特性
- 原子性(Atomicity):事务是最小执行单元,不可分割。
- 一致性(Consistency):事务前后数据状态一致。
- 隔离性(Isolation):并发事务互不干扰。
- 持久性(Durability):事务提交后数据永久保存。
2. Spring 事务配置
步骤:
-
添加依赖(已包含在
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>spring-boot-starter-data-jdbc
或jpa
中): -
启用事务管理(通常无需显式添加,Spring Boot 自动配置):
@SpringBootApplication
@EnableTransactionManagement // 可选,一般不需要
public class App { ... } -
在方法上添加
@Transactional
:@Service
public class StudentService {@Autowired private StudentMapper studentMapper; @Transactional public void saveStudent(Student student) { studentMapper.insert(student); // 如果这里抛出异常,前面的插入也会回滚 int i = 1 / 0; }
}
3. 事务隔离级别(Isolation)
级别 | 问题 |
---|---|
READ_UNCOMMITTED |
脏读、不可重复读、幻读 |
READ_COMMITTED |
不可重复读、幻读 |
REPEATABLE_READ |
幻读 |
SERIALIZABLE |
无问题,但性能最低 |
默认使用数据库默认级别(MySQL 为
REPEATABLE_READ
)。
4. 事务传播行为(Propagation)
Spring 定义了多种传播机制,常见如下:
行为 | 说明 |
---|---|
REQUIRED (默认) |
有事务则加入,无则新建 |
REQUIRES_NEW |
挂起当前事务,新建一个 |
SUPPORTS |
有则加入,无则非事务执行 |
NOT_SUPPORTED |
不支持事务 |
NEVER |
绝不允许事务 |
MANDATORY |
必须运行在事务中 |
传播机制是 Spring 控制的,与数据库无关。
八、RESTful 风格与控制器
使用 @RestController
@RestController
@RequestMapping("/students")
public class StudentController {
@Autowired
private StudentService studentService;
@GetMapping
public List<Student> getAll() {
return studentService.findAll();
}
@PostMapping
public String add(@RequestBody Student student) {
studentService.save(student);
return "success";
}
@PutMapping("/{id}")
public String update(@PathVariable Long id, @RequestBody Student student) {
student.setId(id);
studentService.update(student);
return "updated";
}
@DeleteMapping("/{id}")
public String delete(@PathVariable Long id) {
studentService.delete(id);
return "deleted";
}
}
✅
@RestController = @Controller + @ResponseBody
,所有方法返回 JSON 数据。
九、总结
模块 | 关键点 |
---|---|
MyBatis 整合 | 依赖 + 配置 + Mapper + XML |
参数传递 | 单参直接用,多参用 @Param |
动态 SQL | <if> , <where> , <foreach> , <bind> |
关联查询 | association (一对一),collection (一对多) |
缓存机制 | 一级缓存(会话级)、二级缓存(应用级) |
AOP | 动态代理实现横切逻辑 |
事务管理 | @Transactional 控制 ACID 与传播机制 |
十、学习建议
- 动手实践:搭建一个完整项目,实现增删改查 + 分页 + 权限。
- 阅读官方文档:MyBatis 官网、Spring Boot Docs
- 使用工具:MyBatis-X、Postman、Swagger。
- 深入源码 :了解
SqlSessionFactory
、MapperProxy
的创建过程。
📌 结语:MyBatis 是连接 Java 与数据库的桥梁,掌握它不仅能写出高效的 SQL,更能理解 ORM 的本质。结合 Spring Boot 和 AOP,你可以轻松构建稳定、可维护的企业级应用。
如果你觉得这篇文章有帮助,请点赞、收藏、分享!持续更新更多 Java 实战干货。