Mybatis一个SQL的执行过程


Mybatis的所有语句的执行都是通过SqlSession对象来操作的,SqlSession是由SqlSessionFactory类生成的。首先根据配置文件来创建一个SqlSessionFactory,然后调用openSession来获取一个SqlSession。

1

openSession方法主要是调用openSessionFromDataSource方法返回一个DefaultSqlSession对象:

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;
}

之后根据这个DefaultSqlSession对象来获取MapperProxy对象:

2

MapperProxyFactory通过动态代理访问Dao层中的mapper接口

public class MapperProxyFactory<T> {
    private final Class<T> mapperInterface;
    private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap();

    public MapperProxyFactory(Class<T> mapperInterface) {
        this.mapperInterface = mapperInterface;
    }

    public Class<T> getMapperInterface() {
        return this.mapperInterface;
    }

    public Map<Method, MapperMethod> getMethodCache() {
        return this.methodCache;
    }

    protected T newInstance(MapperProxy<T> mapperProxy) {
        return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
    }

    public T newInstance(SqlSession sqlSession) {
        MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
        return this.newInstance(mapperProxy);
    }
}

具体的SQL执行还是使用的Excutor:

3

MapperProxy执行SQL会触发invoke方法,最后使用execute来执行CRUD:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
        //代理以后,所有Mapper的方法调用时,都会调用这个invoke方法
        //并不是任何一个方法都需要执行调用代理对象进行执行,如果这个方法是Object中通用的方法(toString、hashCode等)无需执行
        if (Object.class.equals(method.getDeclaringClass())) {
            return method.invoke(this, args);
        }

        if (this.isDefaultMethod(method)) {
            return this.invokeDefaultMethod(proxy, method, args);
        }
    } catch (Throwable var5) {
        throw ExceptionUtil.unwrapThrowable(var5);
    }

    //去缓存中找MapperMethod
    MapperMethod mapperMethod = this.cachedMapperMethod(method);
    //执行
    return mapperMethod.execute(this.sqlSession, args);
}

execute内部调用SqlSession的CRUD方法,比如selectList方法:

public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
        MappedStatement ms = configuration.getMappedStatement(statement);
        //CRUD实际上是交给Excetor去处理, excutor其实也只是穿了个马甲而已,小样,别以为穿个马甲我就不认识你嘞!
        return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
    } catch (Exception e) {
        throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
        ErrorContext.instance().reset();
    }
}

然后,通过一层一层的调用,最终会来到doQuery方法, 这儿咱们就随便找个Excutor看看doQuery方法的实现吧,我这儿选择了SimpleExecutor:

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());
        //StatementHandler封装了Statement, 让 StatementHandler 去处理
        return handler.<E>query(stmt, resultHandler);
    } finally {
        closeStatement(stmt);
    }
}

接下来,咱们看看StatementHandler 的一个实现类 PreparedStatementHandler(这也是我们最常用的,封装的是PreparedStatement), 看看它使怎么去处理的:

public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();
    //结果交给了ResultSetHandler 去处理
    return resultSetHandler.<E> handleResultSets(ps);
}

参考文章:

https://blog.csdn.net/majinggogogo/article/details/72179560


文章作者: Cody_
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Cody_ !
评论
 上一篇
MySQL的事务日志 MySQL的事务日志
MySQL的日志主要有三种:binlog(二进制日志),redo log(重做日志),undo log(回滚日志) redo log 是物理日志,undo log 和 binlog 是逻辑日志 binlog二进制日志是server层的无论
2021-01-28
下一篇 
@Autowired注解自动注入的原理 @Autowired注解自动注入的原理
@Autowired自动注入是由AutowiredAnnotationBeanPostProcessor实现的,这个类实现了MergedBeanDefinitionPostProcessor接口,进而实现了postProcessMerged
2021-01-15
  目录