思途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 小时前
Spring Boot集成方案 + Elasticsearch向量检索,语义搜索核弹
java·spring boot·python·spring·elasticsearch·spring cloud·系统架构
Absinthe_苦艾酒1 小时前
JVM学习专题(四)对象创建过程
java·jvm·后端
F_D_Z2 小时前
【感知机】感知机(perceptron)模型与几何解释
学习·算法·支持向量机
程序员奈斯2 小时前
苍穹外卖Day10
java
CodeHackerBhx2 小时前
Jenkins
java·运维·jenkins
忘忧人生2 小时前
docker 容器常用命令
java·docker·容器
慕y2743 小时前
Java学习第一百一十部分——CI/CD
java·学习·ci/cd
柊二三3 小时前
spring boot开发中的资源处理等问题
java·spring boot·后端
一枚小小程序员哈3 小时前
基于springboot的宠物商城设计与实现
java·spring boot·spring·eclipse·tomcat·maven·宠物
l1t3 小时前
利用DeepSeek改写并增强测试Duckdb和sqlite的不同插入方法性能
python·sql·sqlite·duckdb