mybatis执行流程
mybatis执行流程
MyBatis执行八步走
上面流程就是MyBatis内部核心流程,咱们来一步步解释下,根据图中步骤,我们可以将这个执行流程分成了8个步骤。
1、读取MyBatis的核心配置文件。
mybatis-config.xml为MyBatis的全局配置文件,用于配置数据库连接、属性、类型别名、类型处理器、插件、环境配置、映射器(mapper.xml)等信息,这个过程中有一个比较重要的部分就是映射文件其实是配在这里的;这个核心配置文件最终会被封装成一个Configuration对象
2、加载映射文件。
映射文件即SQL映射文件,该文件中配置了操作数据库的SQL语句,映射文件是在mybatis-config.xml中加载;可以加载多个映射文件。常见的配置的方式有两种,一种是package扫描包,一种是mapper找到配置文件的位置。
[](javascript:void(0)😉
<!-- 使用包路径,扫描包下所有的接口,这种方式比较方便 -->
<package name="com.mybatis.demo"/>
<!-- resource:使用相对路径的资源引用-->
<!-- url:使用绝对类路径的资源引用-->
<!-- class:使用映射器接口实现类的完全限定类名-->
<mapper resource="xxx.xml"/>
[](javascript:void(0)😉
3、构造会话工厂获取SqlSessionFactory。
这个过程其实是用建造者设计模式使用SqlSessionFactoryBuilder对象构建的,SqlSessionFactory的最佳作用域是应用作用域。
//2. 创建SqlSessionFactory对象实际创建的是DefaultSqlSessionFactory对象
SqlSessionFactory builder = new SqlSessionFactoryBuilder().build(inputStream);
4、创建会话对象SqlSession。
由会话工厂创建SqlSession对象,对象中包含了执行SQL语句的所有方法,每个线程都应该有它自己的 SqlSession 实例。SqlSession的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。 并把执行器放进SqlSession中
//3. 创建SqlSession对象实际创建的是DefaultSqlSession对象
SqlSession sqlSession = builder.openSession();
5、Executor执行器。
是MyBatis的核心,负责SQL语句的生成和查询缓存的维护,它将根据SqlSession传递的参数动态地生成需要执行的SQL语句,同时负责查询缓存的维护
- SimpleExecutor -- SIMPLE 就是普通的执行器。
- ReuseExecutor-执行器会重用预处理语句(PreparedStatements)
- BatchExecutor --它是批处理执行器
1.CachingExecutor 二级缓存执行器
里面修饰了一个BaseExecutor执行器,上面是他的实现类,delegate.query执行上面执行器的.query方法
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
throws SQLException {
Cache cache = ms.getCache();
if (cache != null) {
flushCacheIfRequired(ms);
if (ms.isUseCache() && resultHandler == null) {
ensureNoOutParams(ms, boundSql);
@SuppressWarnings("unchecked")
List<E> list = (List<E>) tcm.getObject(cache, key);
if (list == null) {
list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list); // issue #578 and #116
}
return list;
}
}
return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
2.BaseExecutor执行器
先查询一级缓存,如果一级缓存有,则直接返回缓存中的数据。如果一级缓存没有,则查询数据库queryFromDatabase
@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
if (closed) {
throw new ExecutorException("Executor was closed.");
}
if (queryStack == 0 && ms.isFlushCacheRequired()) {
clearLocalCache();
}
List<E> list;
try {
queryStack++;
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
if (list != null) {
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
queryStack--;
}
if (queryStack == 0) {
for (DeferredLoad deferredLoad : deferredLoads) {
deferredLoad.load();
}
// issue #601
deferredLoads.clear();
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
// issue #482
clearLocalCache();
}
}
return list;
}
3SimpleExector执行器
在执行到查询数据库后,后面会调用执行器的查询数据库方法,
@Override
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.query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
StatementHandler里面有2个属性,parameterHandler处理入参, resultSetHandler处理返回结果
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
String sql = boundSql.getSql();
statement.execute(sql);
//设置结果,结果处理器resultSetHandler
return resultSetHandler.handleResultSets(statement);
}
6、MappedStatement对象。
MappedStatement是对解析的SQL的语句封装,一个MappedStatement代表了一个sql语句标签,如下:
<!--一个动态sql标签就是一个`MappedStatement`对象-->
<select id="selectUserList" resultType="com.mybatis.User">
select * from t_user
</select>
7、输入参数映射
输入参数类型可以是基本数据类型,也可以是Map、List、POJO类型复杂数据类型,这个过程类似于JDBC的预编译处理参数的过程,有两个属性 parameterType和parameterMap
8、封装结果集。
可以封装成多种类型可以是基本数据类型,也可以是Map、List、POJO类型复杂数据类型。封装结果集的过程就和JDBC封装结果集是一样的。也有两个常用的属性resultType和resultMap。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步