当前位置: 首页 > news >正文

MyBatis 源码解析:Executor 接口的核心作用


摘要

在 MyBatis 中,Executor 接口是执行 SQL 语句和管理缓存的核心组件。它的存在使得 MyBatis 可以灵活地处理数据库操作,支持一级缓存和二级缓存等功能。本文将通过自定义实现一个 Executor 接口,带你深入探讨 MyBatis 中 Executor 的核心作用,并帮助你更好地掌握 SQL 执行和缓存管理的机制。


前言

Executor 是 MyBatis 框架中的核心组件之一,负责执行 SQL 语句、处理结果集以及管理缓存。理解 Executor 的作用和实现机制,对于深入掌握 MyBatis 的工作原理至关重要。本文将通过自定义实现一个简化版的 Executor 接口,并对 MyBatis 的 Executor 进行源码解析,帮助你全面理解其功能和实现。


自定义实现:简化版 Executor 接口

目标与功能

我们将实现一个简化版的 Executor 接口,该接口将支持执行 SQL 语句、处理结果集并管理一级缓存。通过这个实现,我们可以更好地理解 MyBatis 是如何设计和管理 SQL 执行和缓存的。

核心流程

  1. 执行 SQL 语句:提供执行 SQL 语句的方法,支持基本的增删改查操作。
  2. 结果集处理:将 SQL 执行的结果映射到 Java 对象中。
  3. 缓存管理:实现一级缓存功能,提升查询效率。

实现过程

1. 定义 Executor 接口

我们首先定义 Executor 接口,包含了执行 SQL 语句和管理缓存的方法。

/*** Executor 接口,定义了 MyBatis 中执行 SQL 和管理缓存的核心操作。*/
public interface Executor {<T> T query(String statement, Object parameter);int update(String statement, Object parameter);void commit();void rollback();void close();
}
2. 实现 SimpleExecutor 类

SimpleExecutor 类是 Executor 接口的一个简化实现类,负责具体执行 SQL 语句,并管理一级缓存。

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;/*** SimpleExecutor 是 Executor 接口的一个简化实现。* 它负责执行 SQL 语句,并管理一级缓存。*/
public class SimpleExecutor implements Executor {private final Connection connection;private final Map<String, Object> localCache = new HashMap<>();  // 一级缓存public SimpleExecutor(Connection connection) {this.connection = connection;}@Overridepublic <T> T query(String statement, Object parameter) {String cacheKey = statement + ":" + parameter;if (localCache.containsKey(cacheKey)) {// 命中缓存,直接返回结果System.out.println("Cache hit for key: " + cacheKey);return (T) localCache.get(cacheKey);}try (PreparedStatement pstmt = connection.prepareStatement(statement)) {// 这里为了简化,只支持单一参数设置pstmt.setObject(1, parameter);try (ResultSet rs = pstmt.executeQuery()) {if (rs.next()) {T result = (T) rs.getObject(1);localCache.put(cacheKey, result);  // 缓存查询结果return result;}}} catch (SQLException e) {// 实际开发中,应该记录详细的日志,并根据需求进行进一步处理throw new RuntimeException("Error executing query", e);}return null;}@Overridepublic int update(String statement, Object parameter) {try (PreparedStatement pstmt = connection.prepareStatement(statement)) {pstmt.setObject(1, parameter);int rows = pstmt.executeUpdate();// 清空缓存,避免脏读localCache.clear();return rows;} catch (SQLException e) {throw new RuntimeException("Error executing update", e);}}@Overridepublic void commit() {try {connection.commit();} catch (SQLException e) {throw new RuntimeException("Failed to commit transaction", e);}}@Overridepublic void rollback() {try {connection.rollback();} catch (SQLException e) {throw new RuntimeException("Failed to rollback transaction", e);}}@Overridepublic void close() {try {connection.close();} catch (SQLException e) {throw new RuntimeException("Failed to close connection", e);}}
}
  • query 方法:执行查询操作,并将结果存储到一级缓存中。每次查询前都会检查缓存,命中则直接返回缓存结果。
  • update 方法:执行更新操作,并清空一级缓存,防止读取到不一致的数据。
  • commitrollback 方法:用于事务管理,确保数据的一致性。
  • close 方法:关闭数据库连接,确保资源不被泄露。
3. 测试 SimpleExecutor

我们编写一个简单的测试类来验证 SimpleExecutor 的功能。

import java.sql.Connection;
import java.sql.DriverManager;public class SimpleExecutorTest {public static void main(String[] args) {try {// 模拟数据库连接Connection connection = DriverManager.getConnection("jdbc:h2:mem:testdb", "sa", "");// 初始化 ExecutorSimpleExecutor executor = new SimpleExecutor(connection);// 执行 SQL 操作executor.update("INSERT INTO users (name, age) VALUES ('John', 30)", null);Object result = executor.query("SELECT age FROM users WHERE name = 'John'", null);System.out.println("Query result: " + result);// 提交事务executor.commit();// 再次查询,验证缓存result = executor.query("SELECT age FROM users WHERE name = 'John'", null);System.out.println("Query result from cache: " + result);// 关闭资源executor.close();} catch (Exception e) {e.printStackTrace();}}
}

自定义实现类图

1..*
«interface»
Executor
+query(String statement, Object parameter)
+int update(String statement, Object parameter)
+commit()
+rollback()
+close()
SimpleExecutor
- Connection connection
- Map localCache
+query(String statement, Object parameter)
+int update(String statement, Object parameter)
+commit()
+rollback()
+close()
Connection
Map

代码解析流程图

开始
初始化 Executor
执行 SQL 查询操作
缓存命中?
返回缓存结果
执行查询并缓存结果
执行更新操作
清空缓存
提交或回滚事务
关闭 Executor 并释放资源
结束

源码解析:MyBatis 中的 Executor 接口

1. Executor 的设计与实现

在 MyBatis 中,Executor 是 SQL 执行和缓存管理的核心接口。Executor 的职责包括执行 SQL 语句、处理结果集、管理一级和二级缓存,以及事务的提交与回滚。

public interface Executor {int update(MappedStatement ms, Object parameter) throws SQLException;<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;void commit(boolean required) throws SQLException;void rollback(boolean required) throws SQLException;void close(boolean forceRollback);// 其他方法...
}
  • update 方法:执行 INSERTUPDATEDELETE 操作,并返回受影响的行数。
  • query 方法:执行 SELECT 操作,并返回结果集。
  • commitrollback 方法:用于事务管理,确保数据的一致性。
  • close 方法:关闭 Executor,释放资源,确保数据库连接等资源不被泄露。

2. 缓存管理(续)

  • 一级缓存:默认启用,存储在 Executor 内部。每次查询操作都会首先检查一级缓存,如果命中缓存则直接返回结果,避免重复查询数据库,提高查询效率。
  • 二级缓存:可以通过配置启用,通常存储在 Mapper 对应的 Cache 对象中,用于跨 SqlSession 共享查询结果。二级缓存可以减少数据库访问次数,但需要注意数据一致性的问题。

在 MyBatis 的 Executor 中,缓存管理是非常重要的部分,通过合理地使用一级缓存和二级缓存,可以大幅提升系统的性能。下面我们来看 MyBatis 中 Executor 的源码实现是如何处理这些功能的。

3. MyBatis 中 Executor 的具体实现

在 MyBatis 中,Executor 的具体实现类包括 SimpleExecutorReuseExecutorBatchExecutor 等。这些实现类分别对应不同的执行策略:

  • SimpleExecutor:每次执行 SQL 语句都会打开一个新的数据库连接,适用于简单的执行场景。
  • ReuseExecutor:在执行 SQL 时会重复使用 PreparedStatement,适用于多次执行同一 SQL 语句的场景。
  • BatchExecutor:将多条 SQL 语句批量执行,适用于批量插入、更新等场景,能够显著提升批量操作的性能。

MyBatis 中的 BaseExecutor 类是这些具体实现类的基类,负责实现基本的缓存管理和事务控制逻辑:

public abstract class BaseExecutor implements Executor {protected Transaction transaction;protected Executor wrapper;protected ConcurrentHashMap<CacheKey, Object> localCache = new ConcurrentHashMap<>();protected List<BatchResult> batchResultList = new ArrayList<>();protected Configuration configuration;protected int queryStack = 0;protected boolean closed;@Overridepublic void commit(boolean required) throws SQLException {clearLocalCache();flushStatements();if (required) {transaction.commit();}}@Overridepublic void rollback(boolean required) throws SQLException {clearLocalCache();flushStatements(true);if (required) {transaction.rollback();}}@Overridepublic void close(boolean forceRollback) {try {try {rollback(forceRollback);} finally {if (transaction != null) {transaction.close();}}} catch (SQLException e) {throw new RuntimeException("Error closing transaction.  Cause: " + e);} finally {transaction = null;localCache = null;closed = true;}}// 其他方法...
}
  • commit 方法:在提交事务时,会清空本地缓存并执行所有批量语句。如果配置了 required 参数为 true,则提交事务。
  • rollback 方法:在回滚事务时,同样会清空本地缓存并回滚所有未执行的批量语句。
  • close 方法:关闭 Executor 时,会确保事务被正确回滚并释放相关资源,防止资源泄漏。

总结与互动

通过本文,我们详细探讨了 MyBatis 中 Executor 接口的设计与实现,并通过自定义实现加深了对 Executor 核心功能的理解。掌握这些知识有助于在开发中更好地管理 SQL 执行和缓存,确保事务的正确性和系统的高效性。

如果您觉得这篇文章对您有帮助,请点赞、收藏并关注!此外,欢迎在评论区留言,与我们分享您的见解或提出疑问!



http://www.mrgr.cn/news/19152.html

相关文章:

  • WEB服务与虚拟主机/IIS中间件部署
  • 服务器搭建NFS服务,将文挂载到windows
  • SpringMvc--后续(参数问题)
  • Python世界:文件自动化备份实践
  • 如何开启事务、确认提交事务、事务回滚、自动提交和禁止自动提交?
  • Tomcat部署及优化
  • Leetcode面试经典150题-54.螺旋矩阵
  • 力扣面试150 旋转链表 闭链成环
  • ChatTCP:一款离线TCP数据包分析macOS APP,致力于让分析TCP数据包像看聊天记录一样简单
  • 如何在 Linux Terminal 中使用 Cmd+C复制,Cmd+V粘帖?
  • Docker入门学习-01
  • vue3页面空白-普通函数和箭头函数提升的不同
  • Windows使用ffmpeg获取麦克风数据
  • 激光雷达产品介绍
  • MySQL备份:备份策略、物理备份、mysqldump备份、增量备份、差异备份
  • DeFi是否还存在Alpha机会?Pencils Protocol 带领市场“向前看”
  • 深入理解 Prometheus 数据模型与指标监控
  • MATLAB eig 函数简介:计算特征值和特征向量
  • VS2022使用指定的LLVM版本
  • Linux C++ 开发7 - GDB常用命令汇总(你想了解的都在这)