前言
MyBatis 作为一个强大的持久层框架,其灵活的映射机制和高效的数据库操作在Java开发中得到了广泛应用。其中,MyBatis 的四大核心组件之一 Executor,负责执行SQL语句、管理缓存以及处理查询结果。在本文中,将深度解析 MyBatis Executor 的内部工作原理,并对其一个关键实现组件——CachingExecutor 进行简要介绍。
Executor 的作用与分类
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; }
2.二级缓存处理: 在执行更新操作时,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🌺 |