MyBatis源码系列--4.mybatis源码解析(下)

接着上一篇
分析源码,从编程式的 demo 入手

        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
      
        SqlSession session = sqlSessionFactory.openSession(); 

        BlogMapper mapper = session.getMapper(BlogMapper.class);
         
        Blog blog = mapper.selectBlogById(1);

我们开始第二步源码分析
SqlSession session = sqlSessionFactory.openSession();

会话创建过程

我们知道,第一步获取的sqlSessionFactory是DefaultSqlSessionFactory,所以直接去它的openSession方法查看源码

public class DefaultSqlSessionFactory implements SqlSessionFactory {
    public SqlSession openSession() {
        return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, false);
    }

    private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
        Transaction tx = null;

        DefaultSqlSession var8;
        try {
            Environment environment = this.configuration.getEnvironment();
            //1.先从 Configuration 里面拿到 Enviroment,Enviroment 里面就有事务工厂
            TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
            //2.创建 Transaction
            tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
            //3.创建 Executor
            Executor executor = this.configuration.newExecutor(tx, execType);
            //4.最终返回 DefaultSqlSession,属性包括 Configuration、Executor 对象
            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;
    }

}

1.先从 Configuration 里面拿到 Enviroment,Enviroment 里面就有事务工厂
TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
我们知道这个标签就是配置数据源和事务的,如下

   
        
            
            
                
                
                
                
            
        
    

2.创建 Transaction
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);

  • 如果配置的是 JDBC,则会使用 Connection 对象的 commit()、rollback()、close() 管理事务
  • 如果配置成 MANAGED,会把事务交给容器来管理,比如 JBOSS,Weblogic
  • 如 果 是 Spring + MyBatis , 则 没 有 必 要 配 置 , 因 为 我 们 会 直 接 在applicationContext.xml 里面配置数据源和事务管理器,覆盖 MyBatis 的配置
    可以看看这个方法的三个实现类


    MyBatis源码系列--4.mybatis源码解析(下)_第1张图片
    image.png

    3.创建 Executor
    Executor executor = this.configuration.newExecutor(tx, execType);

 public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
        //第一次判断有木有配置executorType ,没有配置用defaultExecutorType的配置
        executorType = executorType == null ? this.defaultExecutorType : executorType;
        //第二次又判断,是为了,假如有傻子故意把defaultExecutorType配置为null,默认设置SIMPLE
        executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
        Object executor;
        if (ExecutorType.BATCH == executorType) {
            executor = new BatchExecutor(this, transaction);
        } else if (ExecutorType.REUSE == executorType) {
            executor = new ReuseExecutor(this, transaction);
        } else {
            executor = new SimpleExecutor(this, transaction);
        }
        //是否开启了二级缓存,由一个缓存包装类CachingExecutor来执行
        if (this.cacheEnabled) {
            executor = new CachingExecutor((Executor)executor);
        }
        //executor 添加到插件中
        Executor executor = (Executor)this.interceptorChain.pluginAll(executor);
        return executor;
    }

Executor 的基本类型有三种:SIMPLE、BATCH、REUSE,默认是 SIMPLE
(settingsElement()读取默认值),他们都继承了抽象类 BaseExecutor。


MyBatis源码系列--4.mybatis源码解析(下)_第2张图片
image.png

三种类型的区别:

  • SimpleExecutor
    每执行一次 update 或 select,就开启一个 Statement 对象,用完立刻关闭 Statement 对象。
  • ReuseExecutor
    执行 update 或 select,以 sql 作为 key 查找 Statement 对象,存在就使用,不存在就创建,用完后,不关闭 Statement 对象,而是放置于 Map 内,供下一次使用。简言之,就是重复使用 Statement 对象
  • BatchExecutor
    执行 update(没有 select,JDBC 批处理不支持 select),将所
    有 sql 都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存
    了多个 Statement 对象,每个 Statement 对象都是 addBatch()完毕后,等待逐一执行
    executeBatch()批处理。与 JDBC 批处理相同

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


MyBatis源码系列--4.mybatis源码解析(下)_第3张图片
生成DefaultSqlSession时序图.jpg

获得 Mapper 对象

现在我们已经有一个 DefaultSqlSession 了,必须找到 Mapper.xml 里面定义的Statement ID,才能执行对应的 SQL 语句。

找到 Statement ID 有两种方式:

  • 第一种是直接调用 session 的方法,在参数里面传入Statement ID,这种方式属于硬编码,我们没办法知道有多少处调用,修改起来也很麻烦。另一个问题是如果参数传入错误,在编译阶段也是不会报错的,不利于预先发现问题
Blog blog = (Blog) session.selectOne("com.wei.mapper.BlogMapper.selectBlogById", 1);
  • 第二种就是我们的编程式方法,定义一个接口,然后再调用Mapper 接口的方法。由于我们的接口名称跟 Mapper.xml 的 namespace 是对应的,接口的方法跟 statement ID 也都是对应的,所以根据方法就能找到对应的要执行的 SQL。
BlogMapper mapper = session.getMapper(BlogMapper.class);

我们需要了解这个mapper对象是怎么获取的,它到底是一个什么对象(目前从代码来看仅仅是一个接口而已)?
直接跟进DefaultSqlSession 的getMapper方法

public class DefaultSqlSession implements SqlSession {
    public  T getMapper(Class type) {
        return this.configuration.getMapper(type, this);
    }

  ...
}

进入跟进Configuration的getMapper方法

   public  T getMapper(Class type, SqlSession sqlSession) {
        return this.mapperRegistry.getMapper(type, sqlSession);
    }

我们知道,在解析 mapper 标签和 Mapper.xml 的时候已经把接口类型和类型对应的 MapperProxyFactory 放到了一个 Map 中。获取 Mapper 代理对象,实际上是从Map 中获取对应的工厂类后,调用MapperRegistry的getMapper方法创建对象

public class MapperRegistry {

    private final Configuration config;

    //接口类型和类型对应的 MapperProxyFactory
    private final Map, MapperProxyFactory> knownMappers = new HashMap();

    public MapperRegistry(Configuration config) {
        this.config = config;
    }

   public  T getMapper(Class type, SqlSession sqlSession) {
        MapperProxyFactory mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
        if (mapperProxyFactory == null) {
            throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
        } else {
            try {
                //跟进代码可知通过jdk动态代理获取一个代理对象
                return mapperProxyFactory.newInstance(sqlSession);
            } catch (Exception var5) {
                throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
            }
        }
    }
}

mapperProxyFactory.newInstance(sqlSession);
跟进代码可知通过jdk动态代理获取一个代理对象

public class MapperProxyFactory {
    private final Class mapperInterface;
    private final Map methodCache = new ConcurrentHashMap();

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

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

    public Map getMethodCache() {
        return this.methodCache;
    }

    protected T newInstance(MapperProxy mapperProxy) {
        //因为mapper都是接口,通过jdk动态代理实现即可
        return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
    }

    public T newInstance(SqlSession sqlSession) {
        //这个MapperProxy,就是真正的mapper对象,一个代理对象
        MapperProxy mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
        return this.newInstance(mapperProxy);
    }
}

从上面代码可知,mapper最终的对象就是一个MapperProxy 对象(代理对象),而且是jdk动态代理实现,那么肯定实现了invoke方法,代表每次调用mapper的任意方法,都会进入他的invoke方法,我们可以看看这个代理对象MapperProxy 的代码

public class MapperProxy implements InvocationHandler, Serializable {
    private static final long serialVersionUID = -6424540398559729838L;
    private final SqlSession sqlSession;
    private final Class mapperInterface;
    private final Map methodCache;

    public MapperProxy(SqlSession sqlSession, Class mapperInterface, Map methodCache) {
        this.sqlSession = sqlSession;
        this.mapperInterface = mapperInterface;
        this.methodCache = methodCache;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
            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 = this.cachedMapperMethod(method);
        return mapperMethod.execute(this.sqlSession, args);
    }

    private MapperMethod cachedMapperMethod(Method method) {
        return (MapperMethod)this.methodCache.computeIfAbsent(method, (k) -> {
            return new MapperMethod(this.mapperInterface, method, this.sqlSession.getConfiguration());
        });
    }

    private Object invokeDefaultMethod(Object proxy, Method method, Object[] args) throws Throwable {
        Constructor constructor = Lookup.class.getDeclaredConstructor(Class.class, Integer.TYPE);
        if (!constructor.isAccessible()) {
            constructor.setAccessible(true);
        }

        Class declaringClass = method.getDeclaringClass();
        return ((Lookup)constructor.newInstance(declaringClass, 15)).unreflectSpecial(method, declaringClass).bindTo(proxy).invokeWithArguments(args);
    }

    private boolean isDefaultMethod(Method method) {
        return (method.getModifiers() & 1033) == 1 && method.getDeclaringClass().isInterface();
    }
}

注:JDK 动态代理代理,在实现了 InvocationHandler 的代理类里面,需要传入一个被代理对象的实现类,MyBatis 的动态代理缺不需要实现类,因为它只需要根据接口类型+方法的名称,就可以找到Statement ID 了,而唯一要做的一件事情也是这件,所以不需要实现类,在 MapperProxy里面直接执行逻辑(也就是执行 SQL)就可以了。

总结:获得 Mapper 对象的过程,实质上是获取了一个 MapperProxy 的代理对象。
MapperProxy 中有 sqlSession、mapperInterface、methodCache


MyBatis源码系列--4.mybatis源码解析(下)_第4张图片
image.png
MyBatis源码系列--4.mybatis源码解析(下)_第5张图片
生成Mapper对象时序图.jpg

执行 SQL

我们来到最后一步Blog blog = mapper.selectBlogById(1);真正执行sql

由于所有的 Mapper 都是 MapperProxy 代理对象,所以任意的方法都是执行MapperProxy 的 invoke()方法,那我们直接看MapperProxy 的invoke方法即可

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
            //Object 本身的方法不需要去执行 SQL
            if (Object.class.equals(method.getDeclaringClass())) {
                return method.invoke(this, args);
            }
            //Java 8 中接口的默认方法(jdk8支持接口有默认实现)不需要去执行 SQL
            if (this.isDefaultMethod(method)) {
                return this.invokeDefaultMethod(proxy, method, args);
            }
        } catch (Throwable var5) {
            throw ExceptionUtil.unwrapThrowable(var5);
        }
        // 获取缓存,保存了方法签名和接口方法的关系
        MapperMethod mapperMethod = this.cachedMapperMethod(method);
        return mapperMethod.execute(this.sqlSession, args);
    }

可以断点进去看看传入的值
从这里debug进去 Blog blog = mapper.selectBlogById(1);


MyBatis源码系列--4.mybatis源码解析(下)_第6张图片
image.png

this.cachedMapperMethod(method); 跟进这个代码看看

private MapperMethod cachedMapperMethod(Method method) {
        return (MapperMethod)this.methodCache.computeIfAbsent(method, (k) -> {
            return new MapperMethod(this.mapperInterface, method, this.sqlSession.getConfiguration());
        });
}

public class MapperMethod {
    private final MapperMethod.SqlCommand command;
    private final MapperMethod.MethodSignature method;

    public MapperMethod(Class mapperInterface, Method method, Configuration config) {
        //调用一个内部类,获取要执行的具体mapper中对应的Statement
        this.command = new MapperMethod.SqlCommand(config, mapperInterface, method);
        //调用一个内部类,获取要执行的具体mapper接口方法
        this.method = new MapperMethod.MethodSignature(config, mapperInterface, method);
    }

    public static class SqlCommand {
        private final String name;
        private final SqlCommandType type;

        public SqlCommand(Configuration configuration, Class mapperInterface, Method method) {
            String methodName = method.getName();
            Class declaringClass = method.getDeclaringClass();
            //跟进接口类型,方法名,对应configuration中的xml配置匹配到mapper中对应的Statement
            MappedStatement ms = this.resolveMappedStatement(mapperInterface, methodName, declaringClass, configuration);
           ... 
                //找到mapper.xml中的id,如:com.wei.mapper.BlogMapper.selectBlogById
                this.name = ms.getId();
                //找到mapper.xml中的type,如:SELECT
                this.type = ms.getSqlCommandType();
                if (this.type == SqlCommandType.UNKNOWN) {
                    throw new BindingException("Unknown execution method for: " + this.name);
                }
               ...
         }
    }


    public static class MethodSignature {
        private final boolean returnsMany;
        private final boolean returnsMap;
        private final boolean returnsVoid;
        private final boolean returnsCursor;
        private final boolean returnsOptional;
        private final Class returnType;
        private final String mapKey;
        private final Integer resultHandlerIndex;
        private final Integer rowBoundsIndex;
        private final ParamNameResolver paramNameResolver;

        public MethodSignature(Configuration configuration, Class mapperInterface, Method method) {
            Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface);
            if (resolvedReturnType instanceof Class) {
                this.returnType = (Class)resolvedReturnType;
            } else if (resolvedReturnType instanceof ParameterizedType) {
                this.returnType = (Class)((ParameterizedType)resolvedReturnType).getRawType();
            } else {
                this.returnType = method.getReturnType();
            }

            this.returnsVoid = Void.TYPE.equals(this.returnType);
            this.returnsMany = configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray();
            this.returnsCursor = Cursor.class.equals(this.returnType);
            this.returnsOptional = Optional.class.equals(this.returnType);
            this.mapKey = this.getMapKey(method);
            this.returnsMap = this.mapKey != null;
            this.rowBoundsIndex = this.getUniqueParamIndex(method, RowBounds.class);
            this.resultHandlerIndex = this.getUniqueParamIndex(method, ResultHandler.class);
            this.paramNameResolver = new ParamNameResolver(configuration, method);
        }

     }
}

以上代码可以看看内部注释,主要就是获取一个MapperMethod对象,里面有两个属性,一个是 SqlCommand , 一 个 是MethodSignature,这两个都是 MapperMethod 的内部类,断点值如下图所示:

MyBatis源码系列--4.mybatis源码解析(下)_第7张图片
image.png

我们接着跟进mapperMethod.execute(this.sqlSession, args); 方法

public Object execute(SqlSession sqlSession, Object[] args) {
        Object result;
        Object param;
        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);
                if (this.method.returnsOptional() && (result == null || !this.method.getReturnType().equals(result.getClass()))) {
                    result = Optional.ofNullable(result);
                }
            }
            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;
        }
    }

在这一步,根据不同的 type 和返回类型:
调用 convertArgsToSqlCommandParam()将参数转换为 SQL 的参数。
调用 sqlSession 的 insert()、update()、delete()、selectOne ()方法,我们以查询为例,会走到 selectOne()方法

public class DefaultSqlSession implements SqlSession {
    public  T selectOne(String statement, Object parameter) {
        //最终还是调用到selectList
        List 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;
        }
    }

    public  List selectList(String statement, Object parameter) {
        return this.selectList(statement, parameter, RowBounds.DEFAULT);
    }

    public  List 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;
    }
  ...
}

在 selectList()中,我们先根据 command name(Statement ID)从 Configuration
中拿到 MappedStatement,这个 ms 上面有我们在 xml 中配置的所有属性,包括 id、
statementType、sqlSource、useCache、入参、出参等等
我们断点看看:
从map里面找到对应的ms


MyBatis源码系列--4.mybatis源码解析(下)_第8张图片
image.png
MyBatis源码系列--4.mybatis源码解析(下)_第9张图片
image.png

最终调用this.executor.query(ms, this.wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
即执行了 Executor 的 query()方法
我们知道Executor 有三种基本类型SIMPLE/REUSE/BATCH,还有一种包装类型,CachingExecutor。

那么在这里到底会选择哪一种执行器呢?

回过头去看看 DefaultSqlSession 在初始化的时候是怎么赋值的,这个就是我们的会话创建过程,

  • 如果启用了二级缓存,就会先调用 CachingExecutor 的 query()方法,里面有缓存相关的操作,然后才是再调用基本类型的执行器,比如默认的 SimpleExecutor
  • 如果没有开启二级缓存,先会走到 BaseExecutor 的 query()方法(否则会先走到 CachingExecutor)
MyBatis源码系列--4.mybatis源码解析(下)_第10张图片
image.png

接下来以两种方式来分析源码:
第一种是没开启二级缓存,走BaseExecutor 的 query()方法,我们跟进代码看看

public abstract class BaseExecutor implements Executor {
    private static final Log log = LogFactory.getLog(BaseExecutor.class);
    protected Transaction transaction;
    protected Executor wrapper;
    protected ConcurrentLinkedQueue deferredLoads;
    protected PerpetualCache localCache;//一级缓存对象
    protected PerpetualCache localOutputParameterCache;
    protected Configuration configuration;
    protected int queryStack;
    private boolean closed;

    public  List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
        //获取sql语句,和参数值
        BoundSql boundSql = ms.getBoundSql(parameter);
       //获取缓存key(id+sql语句+参数值等等组成)
        //如:-525700837:2796097031:com.wei.mapper.BlogMapper.selectBlogById:0:2147483647:select //* from blog where bid = ?:1:development
        CacheKey key = this.createCacheKey(ms, parameter, rowBounds, boundSql);

        return this.query(ms, parameter, rowBounds, resultHandler, key, boundSql);
    }

    public  List 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 (this.closed) {
            throw new ExecutorException("Executor was closed.");
        } else {
            if (this.queryStack == 0 && ms.isFlushCacheRequired()) {
                this.clearLocalCache();
            }

            List list;
            try {
                ++this.queryStack;
                //先从一级缓存获取  
                list = resultHandler == null ? (List)this.localCache.getObject(key) : null;
                if (list != null) {
                    this.handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
                } else {
                    //一级缓存中没有数据,直接查询数据库,跟进此代码
                    list = this.queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
                }
            } finally {
                --this.queryStack;
            }

            if (this.queryStack == 0) {
                Iterator var8 = this.deferredLoads.iterator();

                while(var8.hasNext()) {
                    BaseExecutor.DeferredLoad deferredLoad = (BaseExecutor.DeferredLoad)var8.next();
                    deferredLoad.load();
                }

                this.deferredLoads.clear();
                if (this.configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
                    this.clearLocalCache();
                }
            }

            return list;
        }
    }
}

跟进 this.queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql); 方法

  private  List queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
        //把这个key set到一级缓存中,value相当于一个占位符而已
        this.localCache.putObject(key, ExecutionPlaceholder.EXECUTION_PLACEHOLDER);

        List list;
        try {
            //最终的执行query方法,根据配置来走不同的SIMPLE/REUSE/BATCH执行器
            list = this.doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
        } finally {
            //一级缓存删除这个key
            this.localCache.removeObject(key);
        }
        //重新真正set 到一级缓存中
        this.localCache.putObject(key, list);
        if (ms.getStatementType() == StatementType.CALLABLE) {
            this.localOutputParameterCache.putObject(key, parameter);
        }

        return list;
    }

//最终的执行query方法,根据配置来走不同的SIMPLE/REUSE/BATCH执行器
list = this.doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
继续跟进这个方法,我们配置的是默认的SimpleExecutor

public class SimpleExecutor extends BaseExecutor {
      public  List doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        Statement stmt = null;

        List var9;
        try {
            Configuration configuration = ms.getConfiguration();
            //创建StatementHandler对象,根据配置有三种可选(SimpleStatementHandler/PreparedStatementHandler/CallableStatementHandler)
            StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
            //预处理,set参数之类的
            stmt = this.prepareStatement(handler, ms.getStatementLog());
            //最终执行
            var9 = handler.query(stmt, resultHandler);
        } finally {
            this.closeStatement(stmt);
        }

        return var9;
    }
}

//创建StatementHandler对象,根据配置有三种可选(SimpleStatementHandler/PreparedStatementHandler/CallableStatementHandler)
StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
跟进代码,我们用的是PreparedStatementHandler

    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  加入到插件中,目前我们知道还有Executor也加入到插件中
        StatementHandler statementHandler = (StatementHandler)this.interceptorChain.pluginAll(statementHandler);
        return statementHandler;
    }
MyBatis源码系列--4.mybatis源码解析(下)_第11张图片
image.png

跟进这个new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); 代码

public class PreparedStatementHandler extends BaseStatementHandler {
    public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
//       跟进super
       super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
    }
}

接着跟进super

public abstract class BaseStatementHandler implements StatementHandler {
    protected final Configuration configuration;
    protected final ObjectFactory objectFactory;
    protected final TypeHandlerRegistry typeHandlerRegistry;
    protected final ResultSetHandler resultSetHandler;
    protected final ParameterHandler parameterHandler;
    protected final Executor executor;
    protected final MappedStatement mappedStatement;
    protected final RowBounds rowBounds;
    protected BoundSql boundSql;

    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 = this.configuration.getTypeHandlerRegistry();
        this.objectFactory = this.configuration.getObjectFactory();
        if (boundSql == null) {
            this.generateKeys(parameterObject);
            boundSql = mappedStatement.getBoundSql(parameterObject);
        }

        this.boundSql = boundSql;
         //这里创建了parameterHandler 
        this.parameterHandler = this.configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
         //这里创建了resultSetHandler
        this.resultSetHandler = this.configuration.newResultSetHandler(executor, mappedStatement, rowBounds, this.parameterHandler, resultHandler, boundSql);
    }

这里创建了两个很重要的对象parameterHandler 和resultSetHandler,都是包含在StatementHandler 对象中的属性 ,并且跟进这个创建对象的方法,都会发现,这两个对象也加入了interceptorChain

 parameterHandler = (ParameterHandler)this.interceptorChain.pluginAll(parameterHandler);
        ResultSetHandler resultSetHandler = (ResultSetHandler)this.interceptorChain.pluginAll(resultSetHandler);

稍微提一下,这个插件对象

public class InterceptorChain {
    //就是一个list的拦截器,可以全局配置,在几个组件中做拦截功能,
//目前有4个组件都加入到这个list中(Executor/StatementHandler/
ParameterHandler/ResultSetHandler )
    private final List interceptors = new ArrayList();

    public InterceptorChain() {
    }

    public Object pluginAll(Object target) {
        Interceptor interceptor;
        for(Iterator var2 = this.interceptors.iterator(); var2.hasNext(); target = interceptor.plugin(target)) {
            interceptor = (Interceptor)var2.next();
        }

        return target;
    }

关于这个插件,我们在下一篇《5.MyBatis 插件原理与自定义插件》中会详细介绍

//回到之前的代码最终会执行
var9 = handler.query(stmt, resultHandler); 跟进这个方法,就会找到原生的jdbc操作数据库的代码,这里就不继续分析,大家可以debug
至于第二种配置了二级缓存的方式,

 public  List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
        Cache cache = ms.getCache();
         //先判断是mapper.xml 否配置缓存标签,如果没配置不能走缓存,
       //这个逻辑告诉我们,即使在全局配置文件配置开启了二级缓存  
   //但是单个mapper映射文件没有配置,也是不生效的
        if (cache != null) {
            this.flushCacheIfRequired(ms);
            if (ms.isUseCache() && resultHandler == null) {
                this.ensureNoOutParams(ms, boundSql);
                List list = (List)this.tcm.getObject(cache, key);
                if (list == null) {
                      //缓存没有数据,直接走BaseExecutor的query方法
                    list = this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
                    //查询成功,放入二级缓存中
                    this.tcm.putObject(cache, key, list);
                }

                return list;
            }
        }
        //没有配置,直接走BaseExecutor的query方法
        return this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
    }
MyBatis源码系列--4.mybatis源码解析(下)_第12张图片
image.png

通过断点可知,这个二级缓存就是一个TransactionalCache 对象

public class TransactionalCacheManager {
    private final Map transactionalCaches = new HashMap();
    ...
}
MyBatis源码系列--4.mybatis源码解析(下)_第13张图片
MapperProxy执行sql时序图.jpg

通过两篇文章,总结一下mybatis用到的所有对象


MyBatis源码系列--4.mybatis源码解析(下)_第14张图片
image.png

——学自咕泡学院

你可能感兴趣的:(MyBatis源码系列--4.mybatis源码解析(下))