前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Mybatis之运行原理

Mybatis之运行原理

作者头像
小土豆Yuki
发布2020-06-15 17:13:55
3180
发布2020-06-15 17:13:55
举报
文章被收录于专栏:洁癖是一只狗洁癖是一只狗

mybatis运行流程是面试必备技能之一,下面我们就来开始我们的讲解

mybatisa层次图

mybatis执行流程

  1. 根据配置文件,初始化出Configuration
  2. 创建DefaultSqlSession对象(里面包含Configuration以及Exector)
  3. DefaultSqlSession.getMapper(),获取Mapper接口对应的MapperProxy;
  4. MapperProxy里面有(DefaultSqlSession)
  5. 执行增删改成
    1. 调用DefaultSqlSession的增删改查(Exector)
    2. 会创建一个StatementHandler对象(同时创建Parameterhandler和ResultSetHandler)
    3. 调用StatementHandler预编译以及设置参数,使用ParamenterHandler给sql设置参数
    4. 调用StateMentHandler的增删改查方法
    5. ResultSetHandler封装结果

我们在详细看看每一步的具体步骤

1.根据配置文件创建SqlSessionFactory

Confuguration封装了多有配置文件的详细信息,把配置文件的信息解析并保存在Configuration对象中,返回包含了Confuguration的DefaultSqlSessionFactory对象,主要步骤如下

  • 创建sqlsessionFactoryBuilder对象
代码语言:javascript
复制
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
        SqlSessionFactory var5;
try {
            XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
            var5 = this.build(parser.parse());
        } catch (Exception var14) {
throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
        } finally {
            ErrorContext.instance().reset();
try {
                inputStream.close();
            } catch (IOException var13) {
            }
        }
return var5;
    }
  • 解析配置文件
代码语言:javascript
复制
public Configuration parse() {
if (this.parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
        } else {
this.parsed = true;
this.parseConfiguration(this.parser.evalNode("/configuration"));
return this.configuration;
        }
    }
private void parseConfiguration(XNode root) {
try {
            Properties settings = this.settingsAsPropertiess(root.evalNode("settings"));
this.propertiesElement(root.evalNode("properties"));
this.loadCustomVfs(settings);
this.typeAliasesElement(root.evalNode("typeAliases"));
this.pluginElement(root.evalNode("plugins"));
this.objectFactoryElement(root.evalNode("objectFactory"));
this.objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
this.reflectorFactoryElement(root.evalNode("reflectorFactory"));
this.settingsElement(settings);
this.environmentsElement(root.evalNode("environments"));
this.databaseIdProviderElement(root.evalNode("databaseIdProvider"));
this.typeHandlerElement(root.evalNode("typeHandlers"));
this.mapperElement(root.evalNode("mappers"));
        } catch (Exception var3) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3);
        }
    }
  • 返回sqlSessionFactoty,把上面解析的配置的Confuguration,放到构造sqlSessionFactory的build
代码语言:javascript
复制
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
    }

2.返回sqlSession的实现类DefultSqlSession对象,它里面包含了Exextor和Configuration,Executor也会创建

主要如下重要步骤

  • 构造sqlsession对象,包含Executor以及Configuration
代码语言:javascript
复制
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
        Transaction tx = null;
        DefaultSqlSession var8;
try {
            Environment environment = this.configuration.getEnvironment();
            TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
            tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
            Executor executor = this.configuration.newExecutor(tx, execType);
            var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
        } catch (Exception var12) {
this.closeTransaction(tx);
throw ExceptionFactory.wrapException("Error opening session.  Cause: " + var12, var12);
        } finally {
            ErrorContext.instance().reset();
        }

return var8;
    }

3.getMaper返回接口的代理对象,包含了sqlSession对象

根据type从MapperRegistry获取代理对象(MapperRegistry是在初始化Configuration绑定的信息),如下图中显示了MapperRegistry的信息。

代码语言:javascript
复制
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
        } else {
try {
return mapperProxyFactory.newInstance(sqlSession);
            } catch (Exception var5) {
throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
            }
        }
    }

4.查询流程

  • 使用代理对象的invoke
代码语言:javascript
复制
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Object.class.equals(method.getDeclaringClass())) {
try {
return method.invoke(this, args);
            } catch (Throwable var5) {
throw ExceptionUtil.unwrapThrowable(var5);
            }
        } else {
            MapperMethod mapperMethod = this.cachedMapperMethod(method);
return mapperMethod.execute(this.sqlSession, args);
        }
    }
  • 在代理对象方法中使用MapperMethod.execute方法执行增删改查
代码语言:javascript
复制
public Object execute(SqlSession sqlSession, Object[] args) {
        Object param;
        Object result;
        switch(this.command.getType()) {
        case INSERT:
            param = this.method.convertArgsToSqlCommandParam(args);
            result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));
break;
        case UPDATE:
            param = this.method.convertArgsToSqlCommandParam(args);
            result = this.rowCountResult(sqlSession.update(this.command.getName(), param));
break;
        case DELETE:
            param = this.method.convertArgsToSqlCommandParam(args);
            result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));
break;
        case SELECT:
if (this.method.returnsVoid() && this.method.hasResultHandler()) {
this.executeWithResultHandler(sqlSession, args);
                result = null;
            } else if (this.method.returnsMany()) {
                result = this.executeForMany(sqlSession, args);
            } else if (this.method.returnsMap()) {
                result = this.executeForMap(sqlSession, args);
            } else if (this.method.returnsCursor()) {
                result = this.executeForCursor(sqlSession, args);
            } else {
                param = this.method.convertArgsToSqlCommandParam(args);
                result = sqlSession.selectOne(this.command.getName(), param);
            }
break;
        case FLUSH:
            result = sqlSession.flushStatements();
break;
default:
throw new BindingException("Unknown execution method for: " + this.command.getName());
        }
if (result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) {
throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ").");
        } else {
return result;
        }
    }
  • 最终也是调用DefalultSqlSession的selectList,且获取MappedStatement(包含每一个执行的方法对应的sql配置)
代码语言:javascript
复制
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
        List var5;
try {
            MappedStatement ms = this.configuration.getMappedStatement(statement);
            var5 = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
        } catch (Exception var9) {
throw ExceptionFactory.wrapException("Error querying database.  Cause: " + var9, var9);
        } finally {
            ErrorContext.instance().reset();
        }

return var5;
    }
  • 使用BaseExecutor获取sql的相关信息(BoundSql)如下图
代码语言:javascript
复制
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
        BoundSql boundSql = ms.getBoundSql(parameter);
        CacheKey key = this.createCacheKey(ms, parameter, rowBounds, boundSql);
return this.query(ms, parameter, rowBounds, resultHandler, key, boundSql);
    }
  • 在使用SimpleExecutor对象doquery(),重点是是四大对象的处理,statementHandler创建,以及使用ParameterHandler处理参数,以及查询结构使用resultHandler进行处理,最后返回结果。
代码语言:javascript
复制
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        Statement stmt = null;

        List var9;
try {
            Configuration configuration = ms.getConfiguration();
            StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
            stmt = this.prepareStatement(handler, ms.getStatementLog());
            var9 = handler.query(stmt, resultHandler);
        } finally {
this.closeStatement(stmt);
        }

return var9;
    }
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-04-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 洁癖是一只狗 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档