思途AOP学习笔记 0806

在现代 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 会自动配置 SqlSessionFactorySqlSessionTemplate


✅ 步骤二:配置文件设置(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. 二级缓存(应用级缓存)

启用步骤:
  1. 开启全局缓存

    mybatis:
    configuration:
    cache-enabled: true

  2. 实体类实现 Serializable

    public class Student implements Serializable { ... }

  3. 在 Mapper XML 中声明缓存

    <cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/>
  • eviction: 回收策略(LRU/FIFO/SOFT/WEAK)
  • flushInterval: 刷新间隔(毫秒)
  • size: 最多缓存对象数
  • readOnly: 是否只读(提高性能)
  1. 在 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 事务配置

步骤:
  1. 添加依赖(已包含在 spring-boot-starter-data-jdbcjpa 中):

    <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
  2. 启用事务管理(通常无需显式添加,Spring Boot 自动配置):

    @SpringBootApplication
    @EnableTransactionManagement // 可选,一般不需要
    public class App { ... }

  3. 在方法上添加 @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 与传播机制

十、学习建议

  1. 动手实践:搭建一个完整项目,实现增删改查 + 分页 + 权限。
  2. 阅读官方文档:MyBatis 官网、Spring Boot Docs
  3. 使用工具:MyBatis-X、Postman、Swagger。
  4. 深入源码 :了解 SqlSessionFactoryMapperProxy 的创建过程。

📌 结语:MyBatis 是连接 Java 与数据库的桥梁,掌握它不仅能写出高效的 SQL,更能理解 ORM 的本质。结合 Spring Boot 和 AOP,你可以轻松构建稳定、可维护的企业级应用。

如果你觉得这篇文章有帮助,请点赞、收藏、分享!持续更新更多 Java 实战干货。

相关推荐
考虑考虑1 小时前
Jpa使用union all
java·spring boot·后端
用户3721574261352 小时前
Java 实现 Excel 与 TXT 文本高效互转
java
浮游本尊3 小时前
Java学习第22天 - 云原生与容器化
java
渣哥4 小时前
原来 Java 里线程安全集合有这么多种
java
间彧5 小时前
Spring Boot集成Spring Security完整指南
java
间彧5 小时前
Spring Secutiy基本原理及工作流程
java
Java水解6 小时前
JAVA经典面试题附答案(持续更新版)
java·后端·面试
洛小豆8 小时前
在Java中,Integer.parseInt和Integer.valueOf有什么区别
java·后端·面试
前端小张同学9 小时前
服务器上如何搭建jenkins 服务CI/CD😎😎
java·后端
ytadpole9 小时前
Spring Cloud Gateway:一次不规范 URL 引发的路由转发404问题排查
java·后端