作者主页: 有来技术
开源项目: youlai-mall vue3-element-admin youlai-boot
仓库主页: Gitee Github GitCode
欢迎点赞 收藏 ⭐留言 如有错误敬请纠正!
MyBatis 作为一个强大的持久层框架,其灵活的映射机制和高效的数据库操作在Java开发中得到了广泛应用。其中,MyBatis 的四大核心组件之一 Executor,负责执行SQL语句、管理缓存以及处理查询结果。在本文中,将深度解析 MyBatis Executor 的内部工作原理,并对其一个关键实现组件——CachingExecutor 进行简要介绍。
Executor是MyBatis的核心组件之一,主要负责以下职责:
执行 SQL 语句: Executor将用户传入的SQL语句交由StatementHandler处理,并执行最终的SQL操作。
缓存管理: 管理MyBatis的一级缓存(本地缓存)和二级缓存(全局缓存)。
结果集映射: 将数据库返回的结果集映射为Java对象。
根据具体实现方式,Executor分为三种主要类型:
SimpleExecutor: 每执行一次update或select,就开启一个Statement对象,用完立即关闭。
ReuseExecutor: 执行update或select,以SQL语句作为key查找Statement对象,存在就使用,不存在就创建,用完不关闭Statement对象,而是放置于Map内,供下一次使用。
BatchExecutor: 批量执行Statement,没有二级缓存功能。
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在执行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 专门用于批量执行 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 通过缓存机制在一级缓存和二级缓存中提高查询性能。其工作原理涉及一级缓存和二级缓存的处理:
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;
}
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持久层框架的关键组件。
Github | Gitee | |
---|---|---|
后端 | youlai-mall | youlai-mall |
前端 | mall-admin | mall-admin |
移动端 | mall-app | mall-app |
Github | Gitee | |
---|---|---|
后端 | youlai-boot | youlai-boot |
前端 | vue3-element-admin | vue3-element-admin |