MyBatis 四大核心组件之 Executor 源码解析

作者主页: 有来技术
开源项目: youlai-mall vue3-element-admin youlai-boot
仓库主页: Gitee Github GitCode
欢迎点赞 收藏 ⭐留言 如有错误敬请纠正!

MyBatis 四大核心组件之 Executor 源码解析_第1张图片

目录

  • 前言
  • Executor 的作用与分类
  • Executor 的源码解析
    • SimpleExecutor
    • ReuseExecutor
    • BatchExecutor
  • CachingExecutor 的作用
  • 结语
  • 开源项目

前言

MyBatis 作为一个强大的持久层框架,其灵活的映射机制和高效的数据库操作在Java开发中得到了广泛应用。其中,MyBatis 的四大核心组件之一 Executor,负责执行SQL语句、管理缓存以及处理查询结果。在本文中,将深度解析 MyBatis Executor 的内部工作原理,并对其一个关键实现组件——CachingExecutor 进行简要介绍。

Executor 的作用与分类

MyBatis 四大核心组件之 Executor 源码解析_第2张图片

Executor是MyBatis的核心组件之一,主要负责以下职责:

  1. 执行 SQL 语句: Executor将用户传入的SQL语句交由StatementHandler处理,并执行最终的SQL操作。

  2. 缓存管理: 管理MyBatis的一级缓存(本地缓存)和二级缓存(全局缓存)。

  3. 结果集映射: 将数据库返回的结果集映射为Java对象。

根据具体实现方式,Executor分为三种主要类型:

  • SimpleExecutor: 每执行一次update或select,就开启一个Statement对象,用完立即关闭。

  • ReuseExecutor: 执行update或select,以SQL语句作为key查找Statement对象,存在就使用,不存在就创建,用完不关闭Statement对象,而是放置于Map内,供下一次使用。

  • BatchExecutor: 批量执行Statement,没有二级缓存功能。

Executor 的源码解析

SimpleExecutor

SimpleExecutor是MyBatis默认的Executor实现,其关键源码如下:

public class SimpleExecutor extends BaseExecutor {

    @Override
    public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
        Statement stmt = null;
        try {
            Configuration configuration = ms.getConfiguration();
            StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
            stmt = prepareStatement(handler, ms.getStatementLog());
            return handler.update(stmt);
        } finally {
            closeStatement(stmt);
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        Statement stmt = null;
        try {
            Configuration configuration = ms.getConfiguration();
            StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
            stmt = prepareStatement(handler, ms.getStatementLog());
            return handler.<E>query(stmt, resultHandler);
        } finally {
            closeStatement(stmt);
        }
    }

    // ... 其他方法 ...
}

ReuseExecutor

ReuseExecutor在执行update或select时,通过SQL语句作为key缓存Statement对象,下次执行相同的SQL语句时直接从缓存中获取:

public class ReuseExecutor extends BaseExecutor {

    private final Map<String, Statement> statementMap = new HashMap<>();

    @Override
    public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
        Statement stmt = null;
        try {
            Configuration configuration = ms.getConfiguration();
            StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
            stmt = prepareStatement(handler, ms.getStatementLog());
            return handler.update(stmt);
        } finally {
            closeStatement(stmt);
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        Statement stmt = statementMap.get(ms.getKey());
        try {
            if (stmt == null) {
                Configuration configuration = ms.getConfiguration();
                StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
                stmt = prepareStatement(handler, ms.getStatementLog());
                List<E> result = handler.<E>query(stmt, resultHandler);
                statementMap.put(ms.getKey(), stmt);
                return result;
            } else {
                return handleQueryResult(ms, parameter, rowBounds, resultHandler, stmt);
            }
        } finally {
            // ...
        }
    }

    // ... 其他方法 ...
}

BatchExecutor

BatchExecutor 专门用于批量执行 Statement,没有二级缓存功能。适用于需要一次性执行多个 SQL 语句的场景。


public class BatchExecutor extends BaseExecutor {
    @Override
    public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
        // 执行更新操作
        return delegate.update(ms, parameter);
    }

    @Override
    @SuppressWarnings("unchecked")
    public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        // 执行查询操作
        return delegate.<E>query(ms, parameter, rowBounds, resultHandler, ms.getKey(), boundSql);
    }
    // ... 其他方法 ...
}

CachingExecutor 的作用

CachingExecutor 通过缓存机制在一级缓存和二级缓存中提高查询性能。其工作原理涉及一级缓存和二级缓存的处理:

  1. 一级缓存处理: 在执行查询操作时,``CachingExecutor 首先通过 delegate 执行SQL语句,然后将查询结果存储到一级缓存中,以提高后续相同查询的性能。
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    // 从缓存中获取结果
    List<E> list = delegate.query(ms, parameter, rowBounds, resultHandler, key, boundSql);

    // 将结果添加到缓存
    tcm.putObject(key, list);

    return list;
}
  1. 二级缓存处理: 在执行更新操作时,CachingExecutor 会清空一级缓存,然后通过 delegate 执行实际的更新操作。在事务提交时,将一级缓存中的数据写入二级缓存中,以便多个 SqlSession 共享相同的数据。
public int update(MappedStatement ms, Object parameter) throws SQLException {
    // 清空一级缓存
    flushCacheIfRequired(ms);

    // 执行更新操作
    int count = delegate.update(ms, parameter);

    // 提交事务时,将缓存数据写入二级缓存
    tcm.commit();

    return count;
}

结语

本文深入解析 MyBatis 四大核心组件之一的 Executor,着重介绍 SimpleExecutor、ReuseExecutor、BatchExecuto r的源码实现,同时补充CacheExecutor的作用与示例。通过源码解析和示例,全面理解MyBatis持久层框架的关键组件。

开源项目

  • SpringCloud + Vue3 微服务商城
Github Gitee
后端 youlai-mall youlai-mall
前端 mall-admin mall-admin
移动端 mall-app mall-app
  • SpringBoot 3+ Vue3 单体权限管理系统
Github Gitee
后端 youlai-boot youlai-boot
前端 vue3-element-admin vue3-element-admin

你可能感兴趣的:(#,Mybatis,mybatis,java,后端)