Mybatis 源码分析(二)

前言

沿着上篇文章,咱们继续分析,没看过的小伙伴可以点下面链接去看看。Mybatis 源码分析(一)icon-default.png?t=M85Bhttps://blog.csdn.net/cfa3288/article/details/127240553?spm=1001.2014.3001.5501


 SqlSession

        程序每一次操作数据库,都需要创建一个会话,我们用OpenSession()方法来创建。接下来看看SqlSession创建过程中做了哪些操作

SqlSession sqlSession = factory.openSession();

        通过前面创建的DefaultSqlSessionFactory的openSession方法来创建 ,默认获取的simple执行器。

@Override
public SqlSession openSession() {
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}

 继续往下看。..

 在解析environment标签的时候会创建TransactionFactory对象,根据事务工厂和默认的执行器类型,创建执行器。最后返回的是一个DefaultSqlSession对象,在这个DefaultSqlSession对象中包括了Configuration和Executor对象

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
        Transaction tx = null;
        try {
            final Environment environment = configuration.getEnvironment();
            // 获取事务工厂
            final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
            // 创建事务
            tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
            // 根据事务工厂和默认的执行器类型,创建执行器
            final Executor executor = configuration.newExecutor(tx, execType);
            return new DefaultSqlSession(configuration, executor, autoCommit);
        } catch (Exception e) {
            closeTransaction(tx); // may have fetched a connection so lets call close()
            throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
        } finally {
            ErrorContext.instance().reset();
        }
    }


public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
        executorType = executorType == null ? defaultExecutorType : executorType;
        executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
        Executor executor;
        if (ExecutorType.BATCH == executorType) {
            executor = new BatchExecutor(this, transaction);
        } else if (ExecutorType.REUSE == executorType) {
            executor = new ReuseExecutor(this, transaction);
        } else {
            // 默认 SimpleExecutor
            executor = new SimpleExecutor(this, transaction);
        }
        // 二级缓存开关,settings 中的 cacheEnabled 默认是 true
        if (cacheEnabled) {
            executor = new CachingExecutor(executor);
        }
        // 植入插件的逻辑,至此,四大对象已经全部拦截完毕
        executor = (Executor) interceptorChain.pluginAll(executor);
        return executor;
    }


public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
        this.configuration = configuration;
        this.executor = executor;
        this.dirty = false;
        this.autoCommit = autoCommit;
    }

总结:创建会话的过程,我们获得了一个DefaultSqlSession,里面包含了Executor,Executor是 SQL的实际执行对象。

 Mapper代理对象

        接下来看下通过getMapper方法获取对应的接口的代理对象的实现原理

// 通过SqlSession中提供的 API方法来操作数据库
UserMapper mapper = sqlSession.getMapper(UserMapper.class);

 进入DefaultSqlSession中查看

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    // mapperRegistry中注册的有Mapper的相关信息 在解析映射文件时 调用过addMapper方法
    return mapperRegistry.getMapper(type, sqlSession);
}

进入getMapper方法

/**
* 获取Mapper接口对应的代理对象
*/
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    // 获取Mapper接口对应的 MapperProxyFactory 对象
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>)
    knownMappers.get(type);
    if (mapperProxyFactory == null) {
        throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
        return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
        throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
}

进入newInstance方法

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

继续

/**
* 创建实现了 mapperInterface 接口的代理对象
*/
protected T newInstance(MapperProxy<T> mapperProxy) {
    // 1:类加载器:2:被代理类实现的接口、3:实现了 InvocationHandler 的触发管理类
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new
    Class[] { mapperInterface }, mapperProxy);
}

最终我们在代码中发现代理对象是通过JDK动态代理创建,返回的代理对象。而且里面也传递了一个实现 了InvocationHandler接口的触发管理类。

 总结:获得Mapper对象的过程,实质上是获取了一个JDK动态代理对象,这个代理会继承Proxy类,实现被代理的接口,里面持有了一个MapperProxy类型的触发管理类。

 SQL执行

接下来我们看看SQL语句的具体执行过程是怎么样的

List<User> list = mapper.selectUserList();

        由于所有的Mapper都是JDK动态代理对象,所以任意的方法都是执行触发管理类MapperProxy的invoke()方法。

MapperProxy.invoke()

我们直接进入到invoke方法中

@Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
            // toString hashCode equals getClass等方法,无需走到执行SQL的流程
            if (Object.class.equals(method.getDeclaringClass())) {
                return method.invoke(this, args);
            } else {
                // 提升获取 mapperMethod 的效率,到 MapperMethodInvoker(内部接口) 的 invoke
                // 普通方法会走到 PlainMethodInvoker(内部类) 的 invoke
                return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
            }
        } catch (Throwable t) {
            throw ExceptionUtil.unwrapThrowable(t);
        }
    }

然后进入到PlainMethodInvoker的invoke方法

@Override
public Object invoke(Object proxy, Method method, Object[] args, SqlSession
sqlSession) throws Throwable {
    // SQL执行的真正起点
    return mapperMethod.execute(sqlSession, args);
}

mapperMethod.execute()

public Object execute(SqlSession sqlSession, Object[] args) {
        Object result;
        // 根据SQL语句的类型调用SqlSession对应的方法
        switch (command.getType()) {
            case INSERT: {
                // 通过 ParamNameResolver 处理args[] 数组 将用户传入的实参和指定参数名称关联起来
                Object param = method.convertArgsToSqlCommandParam(args);
                // sqlSession.insert(command.getName(), param) 调用SqlSession的insert方法
                // rowCountResult 方法会根据 method 字段中记录的方法的返回值类型对结果进行转换
                result = rowCountResult(sqlSession.insert(command.getName(), param));
                break;
            }
            case UPDATE: {
                Object param = method.convertArgsToSqlCommandParam(args);
                result = rowCountResult(sqlSession.update(command.getName(), param));
                break;
            }
            case DELETE: {
                Object param = method.convertArgsToSqlCommandParam(args);
                result = rowCountResult(sqlSession.delete(command.getName(), param));
                break;
            }
            case SELECT:
                if (method.returnsVoid() && method.hasResultHandler()) {
                    // 返回值为空 且 ResultSet通过 ResultHandler处理的方法
                    executeWithResultHandler(sqlSession, args);
                    result = null;
                } else if (method.returnsMany()) {
                    result = executeForMany(sqlSession, args);
                } else if (method.returnsMap()) {
                    result = executeForMap(sqlSession, args);
                } else if (method.returnsCursor()) {
                    result = executeForCursor(sqlSession, args);
                } else {
                    // 返回值为 单一对象的方法
                    Object param = method.convertArgsToSqlCommandParam(args);
                    // 普通 select 语句的执行入口 >>
                    result = sqlSession.selectOne(command.getName(), param);
                    if (method.returnsOptional()
                            && (result == null || !method.getReturnType().equals(result.getClass()))) {
                        result = Optional.ofNullable(result);
                    }
                }
                break;
            case FLUSH:
                result = sqlSession.flushStatements();
                break;
            default:
                throw new BindingException("Unknown execution method for: " + command.getName());
        }
        if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
            throw new BindingException("Mapper method '" + command.getName()
                    + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
        }
        return result;
    }

        在这一步,根据不同的type(INSERT、UPDATE、DELETE、SELECT)和返回类型:

  1. 调用convertArgsToSqlCommandParam()将方法参数转换为SQL的参数。
  2. 调用sqlSession的insert()、update()、delete()、selectOne ()方法。我们以查询为例,会走到 selectOne()方法。
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);

sqlSession.selectOne

        这里来到了对外的接口的默认实现类DefaultSqlSession。 selectOne()最终也是调用了selectList()

@Override
    public <T> T selectOne(String statement, Object parameter) {
        // 来到了 DefaultSqlSession
        // Popular vote was to return null on 0 results and throw exception on too many.
        List<T> list = this.selectList(statement, parameter);
        if (list.size() == 1) {
            return list.get(0);
        } else if (list.size() > 1) {
            throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
        } else {
            return null;
        }
    }

        在SelectList()中,会先根据command name(statement ID) 从Configuration中拿到MappedStatement。ms里面有xml中增删改查标签配置的所有属性,包括id,statementType、sqlSource、useCache、入参、出参等等

private <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
        try {
            MappedStatement ms = configuration.getMappedStatement(statement);
            // 如果 cacheEnabled = true(默认),Executor会被 CachingExecutor装饰
            return executor.query(ms, wrapCollection(parameter), rowBounds, handler);
        } catch (Exception e) {
            throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
        } finally {
            ErrorContext.instance().reset();
        }
    }

然后就执行了Executor的query()方法。Executor是第二步openSession的时候创建的,创建了执行器基本类型之后,依次执行了二级缓存装饰,和插件包装。

所以,如果有被插件包装,这里会先走到插件的逻辑。如果没有显式地在settings中配置cacheEnabled=false,再走到CachingExecutor的逻辑,然后回走到BaseExecutor的query()方法。

CachingExecutor.query()

@Override
    public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
        // 获取SQL
        BoundSql boundSql = ms.getBoundSql(parameterObject);
        // 创建CacheKey:什么样的SQL是同一条SQL?
        CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
        return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
    }

二级缓存的CacheKey是怎么构成的呢?或者说,什么样的查询才能确定是同一个查询呢?在BaseExecutor的createCacheKey方法中,用到了六要素:

@Override
    public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
        if (closed) {
            throw new ExecutorException("Executor was closed.");
        }
        CacheKey cacheKey = new CacheKey();
        // 方法相同
        cacheKey.update(ms.getId());
        // 翻页偏移相同
        cacheKey.update(rowBounds.getOffset());
        cacheKey.update(rowBounds.getLimit());
        // SQL相同
        cacheKey.update(boundSql.getSql());
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry();
        // mimic DefaultParameterHandler logic
        for (ParameterMapping parameterMapping : parameterMappings) {
            if (parameterMapping.getMode() != ParameterMode.OUT) {
                Object value;
                String propertyName = parameterMapping.getProperty();
                if (boundSql.hasAdditionalParameter(propertyName)) {
                    value = boundSql.getAdditionalParameter(propertyName);
                } else if (parameterObject == null) {
                    value = null;
                } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
                    value = parameterObject;
                } else {
                    MetaObject metaObject = configuration.newMetaObject(parameterObject);
                    value = metaObject.getValue(propertyName);
                }
                // 参数值相同
                cacheKey.update(value);
            }
        }
        if (configuration.getEnvironment() != null) {
            // 数据源环境相同
            // issue #176
            cacheKey.update(configuration.getEnvironment().getId());
        }
        return cacheKey;
    }

        也就是说,当方法相同、翻页偏移量相同、SQL相同、参数值相同、数据源环境相同,才会被认为是同一个查询。CacheKey的实际值举例(toString()生成的,debug可以看到

-- -1381545870:4796102018:com.mapper.BlogMapper.selectBlogById:0:214748364
7:select * from blog where bid = ?:1:development

注意看下CacheKey的属性,里面有一个List按顺序存放了这些要素。

private static final int DEFAULT_MULTIPLIER = 37;
private static final int DEFAULT_HASHCODE = 17;
private final int multiplier;
private int hashcode;
private long checksum;
private int count;
private List<Object> updateList

        怎么比较两个CacheKey是否相等呢。如果一上来就是依次比较六要素是否相等,要比较6次,这样效率不高。有没有更高效的方法呢?继承Object的每个类,都有一个hashCode()方法,用来生成哈希码。它是用来在集合中快速判重的。

        在生成CacheKey的时候,Update方法,也更新了CacheKey的hashCode,它是用乘法哈希生成的基数baseHashCode=17,乘法因子multiplier=37

hashcode = multiplier * hashcode + baseHashCode;

        Object中的hashCode()是一个本地方法,通过随机数算法生成(openJDK8,默认可以通过-XX:hashCode修改)。CacheKey中的hashCode()方法进行了重写,返回自己生成的hashCode,为什么要用37作为乘法因子呢?跟String中的31类似。

        CacheKey中的equals也进行了重写,比较CacheKey是否相等

 @Override
    public boolean equals(Object object) {
        if (this == object) {
            return true;
        }
        if (!(object instanceof CacheKey)) {
            return false;
        }

        final CacheKey cacheKey = (CacheKey) object;

        if (hashcode != cacheKey.hashcode) {
            return false;
        }
        if (checksum != cacheKey.checksum) {
            return false;
        }
        if (count != cacheKey.count) {
            return false;
        }

        for (int i = 0; i < updateList.size(); i++) {
            Object thisObject = updateList.get(i);
            Object thatObject = cacheKey.updateList.get(i);
            if (!ArrayUtil.equals(thisObject, thatObject)) {
                return false;
            }
        }
        return true;
    }

        如果哈希值(乘法哈希)、校验值(加法哈希)、要素个数任何一个不相等,都不是同一个查询,最后才循环比较要素,防止哈希碰撞。

        CacheKey生成之后,调用另一个query()方法。

BaseExecutor.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();
        // cache 对象是在哪里创建的? XMLMapperBuilder类 xmlconfigurationElement()
        // 由 <cache> 标签决定
        if (cache != null) {
            // flushCache="true" 清空一级二级缓存 >>
            flushCacheIfRequired(ms);
            if (ms.isUseCache() && resultHandler == null) {
                ensureNoOutParams(ms, boundSql);
                // 获取二级缓存
                // 缓存通过 TransactionalCacheManager、TransactionalCache 管理
                @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;
            }
        }
        // 走到 SimpleExecutor | ReuseExecutor | BatchExecutor
        return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
    }

@SuppressWarnings("unchecked")
    @Override
    public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
        // 异常体系之 ErrorContext
        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()) {
            // flushCache="true"时,即使是查询,也清空一级缓存
            clearLocalCache();
        }
        List<E> list;
        try {
            // 防止递归查询重复处理缓存
            queryStack++;
            // 查询一级缓存
            // ResultHandler 和 ResultSetHandler的区别
            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 (BaseExecutor.DeferredLoad deferredLoad : deferredLoads) {
                deferredLoad.load();
            }
            // issue #601
            deferredLoads.clear();
            if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
                // issue #482
                clearLocalCache();
            }
        }
        return list;
    }


private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
        List<E> list;
        // 先占位
        localCache.putObject(key, EXECUTION_PLACEHOLDER);
        try {
            // 三种 Executor 的区别,看doUpdate  默认Simple
            list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
        } finally {
            // 移除占位符
            localCache.removeObject(key);
        }
        // 写入一级缓存
        localCache.putObject(key, list);
        if (ms.getStatementType() == StatementType.CALLABLE) {
            localOutputParameterCache.putObject(key, parameter);
        }
        return list;
    }

SimpleExecutor.doQuery方法

@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();
            // 注意,已经来到SQL处理的关键对象 StatementHandler >>
            StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
            // 获取一个 Statement对象
            stmt = prepareStatement(handler, ms.getStatementLog());
            // 执行查询
            return handler.query(stmt, resultHandler);
        } finally {
            // 用完就关闭
            closeStatement(stmt);
        }
    }

        在configuration.newStatementHandler()中,new 一个StatementHandler,先得到RontingStatementHandler。

        RontingStatementHandler里面没有任何的实现,是用来创建基本的StatementHandler的。这里会根据MappedStatement里面的statementType决定StatementHandler的类型,默认是PREPARED(STATEMENT、PREPARED、CALLABLE).

public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
        // StatementType 是怎么来的? 增删改查标签中的 statementType="PREPARED",默认值 PREPARED
        switch (ms.getStatementType()) {
            case STATEMENT:
                delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
                break;
            case PREPARED:
                // 创建 StatementHandler 的时候做了什么?
                delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
                break;
            case CALLABLE:
                delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
                break;
            default:
                throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
        }
    }

        StatementHandler里面包含了处理参数的ParameterHandler和处理结果集的ResultSetHandler。这两个对象都是在上面new的时候创建的。

protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
        this.configuration = mappedStatement.getConfiguration();
        this.executor = executor;
        this.mappedStatement = mappedStatement;
        this.rowBounds = rowBounds;

        this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
        this.objectFactory = configuration.getObjectFactory();

        if (boundSql == null) { // issue #435, get the key before calculating the statement
            generateKeys(parameterObject);
            boundSql = mappedStatement.getBoundSql(parameterObject);
        }

        this.boundSql = boundSql;

        // 创建了四大对象的其它两大对象
        // 创建这两大对象的时候分别做了什么?
        this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
        this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
    }

这三个对象都是可以被拦截的四大对象之一,所以在创建之后都要用拦截器进行包装的方法。

public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
        ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
        // 植入插件逻辑(返回代理对象)
        parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
        return parameterHandler;
    }

    public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
                                                ResultHandler resultHandler, BoundSql boundSql) {
        ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
        // 植入插件逻辑(返回代理对象)
        resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
        return resultSetHandler;
    }

    public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
        StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
        // 植入插件逻辑(返回代理对象)
        statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
        return statementHandler;
    }

创建Statement

        用new出来的StatementHandler创建Statement对象

@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();
            // 此时,已经来到了SQL处理的关键对象,StatementHandler
            StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
            // 获取一个statement对象
            stmt = prepareStatement(handler, ms.getStatementLog());
            // 执行查询
            return handler.query(stmt, resultHandler);
        } finally {
            // 用完就关闭
            closeStatement(stmt);
        }
    }

执行查询操作,如果有插件包装,会先走到被拦截的业务逻辑,进入到PreparedStatementHandler中处理

@Override
    public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
        PreparedStatement ps = (PreparedStatement) statement;
        // 到了JDBC的流程
        ps.execute();
        // 处理结果集
        return resultSetHandler.handleResultSets(ps);
    }

执行PreparedStatement的execute方法,后面就是JDBC包中的PreparedStatement的执行了。ResultSetHandler处理结果集,如果有插件包装,会先走到被拦截的业务逻辑。

总结:调用代理对象执行SQL操作的流程

 Mybatis核心对象

对象相关对象作用
Configuration

MapperRegistry

TypeAliasRegistry

TypeHandlerRegistry

包含了MyBatis的所有的配置信息
SqlSession

SqlSessionFactory

DefaultSqlSession

对操作数据库的增删改查的API进行了封装,提供给应用层使用
Executor

BaseExecutor

SimpleExecutor

BatchExecutor

ReuseExecutor

MyBatis执行器,是MyBatis 调度的核 心,负责SQL语句的生成和查询缓存的维 护
StatementHandler

BaseStatementHandler

SimpleStatementHandler

PreparedStatementHandler

CallableStatementHandler

封装了JDBC Statement操作,负责对 JDBC statement 的操作,如设置参数、 将Statement结果集转换成List集合
ParameterHandlerDefaultResultSetHandler把用户传递的参数转换成JDBC Statement 所需要的参数
ResultSetHandlerDefaultResultSetHandler把JDBC返回的ResultSet结果集对象转换 成List类型的集合
MapperProxyMapperProxyFactory触发管理类,用于代理Mapper接口方法
MappedStatement

SqlSource

BoundSql

MappedStatement维护了一条<select|update|delete|insert>节点的 封装,表示一条SQL包括了SQL信息、入 参信息、出参信息

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值