Mybatis源码学习(三)SqlSession详解

前言

上一章节我们学习了SqlSessionFactory的源码,SqlSessionFactory中的方法都是围绕着SqlSession来的.,那么SqlSession又是什么东东呢?这一章节我们就来揭开它的真面目吧!

1. SqlSession源码详解

SqlSession是一个接口类,文档上注明它是mybatis的一个主要的java 接口.官方都说很重要了,那肯定是非常重要.它的主要功能是执行命令,获取mapper和管理事务.
SqlSession有两个实现类,分别是DefaultSqlSessionSqlSessionManager,上一章节也出现过SqlSessionManager,大家还记得吗?SqlSessionManager既实现了SqlSession也实现了SqlSessionFactory.话不多说,详细学习以下两个类的源码吧!
在这里插入图片描述

2. DefaultSqlSession源码详解

2.1DefaultSqlSession源码

public class DefaultSqlSession implements SqlSession {

  /**
   * 全局配置对象
   */
  private final Configuration configuration;
  /**
   * sql执行器
   */
  private final Executor executor;

  /**
   * 是否自动提交
   */
  private final boolean autoCommit;
  /**
   * 是否脏数据
   */
  private boolean dirty;
  /**
   * 游标列表
   */
  private List<Cursor<?>> cursorList;

  /**构造函数
   * @param configuration         核心配置对象
   * @param executor              sql执行器
   * @param autoCommit            是否自动提交
   */
  public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
    this.configuration = configuration;
    this.executor = executor;
    this.dirty = false;
    this.autoCommit = autoCommit;
  }

  /**构造函数
   * @param configuration         核心配置对象
   * @param executor              sql执行器
   */
  public DefaultSqlSession(Configuration configuration, Executor executor) {
    this(configuration, executor, false);
  }

  /**查询单条数据并返回对象
   * @param statement             the statement
   * @param <T>                   返回对象类型
   * @return                      对象
   */
  @Override
  public <T> T selectOne(String statement) {
    return this.selectOne(statement, null);
  }

  /**查询单条数据并返回对象
   * @param statement             the statement
   * @param parameter             sql语句参数
   * @param <T>                   返回对象类型
   * @return                      对象
   */
  @Override
  public <T> T selectOne(String statement, Object parameter) {
    // Popular vote was to return null on 0 results and throw exception on too many.
    //调用selectList
    List<T> list = this.selectList(statement, parameter);
    if (list.size() == 1) {
      //结果为1条数据时,返回第0条
      return list.get(0);
    } else if (list.size() > 1) {
      //结果数大于1时,抛出异常
      throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
    } else {
      //返回null
      return null;
    }
  }

  /**map查询
   * @param statement Unique identifier matching the statement to use.
   * @param mapKey    The property to use as key for each value in the list.
   * @param <K>       返回的map的key的泛型
   * @param <V>       返回的map的值的泛型
   * @return          返回map<K,V>
   */
  @Override
  public <K, V> Map<K, V> selectMap(String statement, String mapKey) {
    //调用selectMap
    return this.selectMap(statement, null, mapKey, RowBounds.DEFAULT);
  }

  /**map查询
   * @param statement Unique identifier matching the statement to use.
   * @param parameter A parameter object to pass to the statement.
   * @param mapKey    The property to use as key for each value in the list.
   * @param <K>       返回的map的key的泛型
   * @param <V>       返回的map的值的泛型
   * @return          返回map<K,V>
   */
  @Override
  public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) {
    //调用selectMap
    return this.selectMap(statement, parameter, mapKey, RowBounds.DEFAULT);
  }

  /**map查询
   * @param statement Unique identifier matching the statement to use.
   * @param parameter A parameter object to pass to the statement.
   * @param mapKey    The property to use as key for each value in the list.
   * @param rowBounds Bounds to limit object retrieval
   * @param <K>       返回的map的key的泛型
   * @param <V>       返回的map的值的泛型
   * @return          返回map<K,V>
   */
  @Override
  public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
    //调用selectList获取结果
    final List<? extends V> list = selectList(statement, parameter, rowBounds);
    //初始化一个默认的Map结果处理器
    final DefaultMapResultHandler<K, V> mapResultHandler = new DefaultMapResultHandler<>(mapKey,
            configuration.getObjectFactory(), configuration.getObjectWrapperFactory(), configuration.getReflectorFactory());
    //初始化一个默认的结果上下文对象
    final DefaultResultContext<V> context = new DefaultResultContext<>();
    for (V o : list) {
      //遍历结果列表,放入context中
      context.nextResultObject(o);
      //使用Map结果处理器处理上下文
      mapResultHandler.handleResult(context);
    }
    //从结果处理器中获取处理完的map<K,V>返回
    return mapResultHandler.getMappedResults();
  }

  /**游标查询
   * @param statement Unique identifier matching the statement to use.
   * @param <T>       返回对象类型
   * @return          对象
   */
  @Override
  public <T> Cursor<T> selectCursor(String statement) {
    return selectCursor(statement, null);
  }

  /**游标查询
   * @param statement Unique identifier matching the statement to use.
   * @param parameter A parameter object to pass to the statement.
   * @param <T>       返回对象类型
   * @return          对象
   */
  @Override
  public <T> Cursor<T> selectCursor(String statement, Object parameter) {
    return selectCursor(statement, parameter, RowBounds.DEFAULT);
  }

  /**游标查询
   * @param statement Unique identifier matching the statement to use.
   * @param parameter A parameter object to pass to the statement.
   * @param rowBounds Bounds to limit object retrieval
   * @param <T>       返回对象类型
   * @return          对象
   */
  @Override
  public <T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds) {
    try {
      //使用全局配置对象中的mappedStatements获取MappedStatement对象
      MappedStatement ms = configuration.getMappedStatement(statement);
      //调用sql处理器查询
      Cursor<T> cursor = executor.queryCursor(ms, wrapCollection(parameter), rowBounds);
      //把游标注册到游标列表中,方便后续统一管理游标
      registerCursor(cursor);
      return cursor;
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

  /**查询列表
   * @param statement Unique identifier matching the statement to use.
   * @param <E>       结果的泛型
   * @return          结果列表
   */
  @Override
  public <E> List<E> selectList(String statement) {
    return this.selectList(statement, null);
  }

  /**查询列表
   * @param statement Unique identifier matching the statement to use.
   * @param parameter A parameter object to pass to the statement.
   * @param <E>       结果的泛型
   * @return          结果列表
   */
  @Override
  public <E> List<E> selectList(String statement, Object parameter) {
    //调用selectList
    return this.selectList(statement, parameter, RowBounds.DEFAULT);
  }

  /**查询列表
   * @param statement Unique identifier matching the statement to use.
   * @param parameter A parameter object to pass to the statement.
   * @param rowBounds Bounds to limit object retrieval
   * @param <E>       结果的泛型
   * @return          结果列表
   */
  @Override
  public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
      //使用全局配置对象中的mappedStatements获取MappedStatement对象
      MappedStatement ms = configuration.getMappedStatement(statement);
      //调用sql处理器查询
      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();
    }
  }

  /**带结果处理器的查询
   * @param statement Unique identifier matching the statement to use.
   * @param parameter A parameter object to pass to the statement.
   * @param handler   ResultHandler that will handle each retrieved row
   */
  @Override
  public void select(String statement, Object parameter, ResultHandler handler) {
    //调用select
    select(statement, parameter, RowBounds.DEFAULT, handler);
  }

  /**带结果处理器的查询
   * @param statement Unique identifier matching the statement to use.
   * @param handler   ResultHandler that will handle each retrieved row
   */
  @Override
  public void select(String statement, ResultHandler handler) {
    select(statement, null, RowBounds.DEFAULT, handler);
  }

  /**带结果处理器的查询
   * @param statement Unique identifier matching the statement to use.
   * @param parameter the parameter
   * @param rowBounds RowBound instance to limit the query results
   * @param handler
   */
  @Override
  public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
    try {
      //使用全局配置对象中的mappedStatements获取MappedStatement对象
      MappedStatement ms = configuration.getMappedStatement(statement);
      //调用sql处理器查询
      executor.query(ms, wrapCollection(parameter), rowBounds, handler);
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

  /**插入数据
   * @param statement Unique identifier matching the statement to execute.
   * @return          影响的行数
   */
  @Override
  public int insert(String statement) {
    //调用insert
    return insert(statement, null);
  }

  /**插入数据
   * @param statement Unique identifier matching the statement to execute.
   * @param parameter A parameter object to pass to the statement.
   * @return          影响的行数
   */
  @Override
  public int insert(String statement, Object parameter) {
    //调用update
    return update(statement, parameter);
  }

  /**更新数据
   * @param statement Unique identifier matching the statement to execute.
   * @return          影响的行数
   */
  @Override
  public int update(String statement) {
    //调用update
    return update(statement, null);
  }

  /**更新数据
   * @param statement Unique identifier matching the statement to execute.
   * @param parameter A parameter object to pass to the statement.
   * @return          影响的行数
   */
  @Override
  public int update(String statement, Object parameter) {
    try {
      //设置脏数据状态为true
      dirty = true;
      //使用全局配置对象中的mappedStatements获取MappedStatement对象
      MappedStatement ms = configuration.getMappedStatement(statement);
      //调用sql处理器更新
      return executor.update(ms, wrapCollection(parameter));
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error updating database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

  /**删除数据
   * @param statement Unique identifier matching the statement to execute.
   * @return          影响的行数
   */
  @Override
  public int delete(String statement) {
    //调用update
    return update(statement, null);
  }

  /**删除数据
   * @param statement Unique identifier matching the statement to execute.
   * @param parameter A parameter object to pass to the statement.
   * @return          影响的行数
   */
  @Override
  public int delete(String statement, Object parameter) {
    //调用更新
    return update(statement, parameter);
  }

  /**
   * 提交事务
   */
  @Override
  public void commit() {
    commit(false);
  }

  /**提交事务
   * @param force     是否强制提交
   */
  @Override
  public void commit(boolean force) {
    try {
      //调用执行器提交事务
      executor.commit(isCommitOrRollbackRequired(force));
      //设置脏数据状态为false
      dirty = false;
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error committing transaction.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

  /**
   * 回滚事务
   */
  @Override
  public void rollback() {
    rollback(false);
  }

  /**回滚事务
   * @param force forces connection rollback
   */
  @Override
  public void rollback(boolean force) {
    try {
      //调用执行器回滚事务
      executor.rollback(isCommitOrRollbackRequired(force));
      //设置脏数据状态为false
      dirty = false;
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error rolling back transaction.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

  /**批量处理
   * @return        返回批量处理的结果
   */
  @Override
  public List<BatchResult> flushStatements() {
    try {
      //调用执行器进行批量操作
      return executor.flushStatements();
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error flushing statements.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

  /**
   * 关闭sqlsession
   */
  @Override
  public void close() {
    try {
      //调用执行器进行关闭
      executor.close(isCommitOrRollbackRequired(false));
      //关闭所有游标
      closeCursors();
      //设置脏数据状态为false
      dirty = false;
    } finally {
      ErrorContext.instance().reset();
    }
  }

  /**
   * 关闭全部游标
   */
  private void closeCursors() {
    if (cursorList != null && !cursorList.isEmpty()) {
      for (Cursor<?> cursor : cursorList) {
        //遍历游标列表,进行关闭操作
        try {
          cursor.close();
        } catch (IOException e) {
          throw ExceptionFactory.wrapException("Error closing cursor.  Cause: " + e, e);
        }
      }
      //清空游标
      cursorList.clear();
    }
  }

  /**获取全局配置对象
   * @return        全局配置对象
   */
  @Override
  public Configuration getConfiguration() {
    return configuration;
  }

  /**获取Mapper<T>的动态代理类
   * @param type  Mapper interface class
   * @param <T>   返回对象的泛型
   * @return      Mapper接口的动态代理类
   */
  @Override
  public <T> T getMapper(Class<T> type) {
    //从核心配置对象中获取mapper, 实际是从mapperRegistry中获取mapper接口的代理工厂,使用代理工厂创建的动态代理类
    return configuration.getMapper(type, this);
  }

  /**获取数据库连接
   * @return      数据库连接
   */
  @Override
  public Connection getConnection() {
    try {
      //调用执行器获取连接
      return executor.getTransaction().getConnection();
    } catch (SQLException e) {
      throw ExceptionFactory.wrapException("Error getting a new connection.  Cause: " + e, e);
    }
  }

  /**
   * 清除缓存
   */
  @Override
  public void clearCache() {
    //调用执行器清除本地缓存
    executor.clearLocalCache();
  }

  /**注册游标
   * @param cursor      游标对象
   * @param <T>         泛型
   */
  private <T> void registerCursor(Cursor<T> cursor) {
    if (cursorList == null) {
      cursorList = new ArrayList<>();
    }
    //把游标加入到cursorList
    cursorList.add(cursor);
  }

  /**判断是否需求提交或者回滚
   * @param force         是否强制提交或回滚
   * @return              是否需求提交或者回滚
   */
  private boolean isCommitOrRollbackRequired(boolean force) {
    //如果不是自动提交并且有脏数据返回true
    //如果强制提交或回滚返回true
    return (!autoCommit && dirty) || force;
  }

  /**将Collection或者数组类型的参数转换成Map
   * @param object      参数对象
   * @return            包装后的对象
   */
  private Object wrapCollection(final Object object) {
    return ParamNameResolver.wrapToMapIfCollection(object, null);
  }

  /**
   * @deprecated Since 3.5.5
   */
  @Deprecated
  public static class StrictMap<V> extends HashMap<String, V> {

    private static final long serialVersionUID = -5741767162221585340L;

    @Override
    public V get(Object key) {
      if (!super.containsKey(key)) {
        throw new BindingException("Parameter '" + key + "' not found. Available parameters are " + this.keySet());
      }
      return super.get(key);
    }

  }

}

DefaultSqlSession的方法分类
1.selectOne(),selectMap(),selectList()为一类,它们的实现都是通过selectList()得到的结构进行处理的
2.selectCursor()
3.select()
4.insert(),update(),delete()为一类,它们的实现都是通过update()
5.实现的事务相关的和其他方法

2.2 configuration.getMappedStatement(statement)

configuration的内部是维护了一个Map<String, MappedStatement> mappedStatements
在获取之前如果还有未完成的Statements,会先执行buildAllStatements()

public MappedStatement getMappedStatement(String id, boolean validateIncompleteStatements) {
    if (validateIncompleteStatements) {
      buildAllStatements();
    }
    return mappedStatements.get(id);
}

那这个Map是什么时候插入值的呢,我们进行代码的跟踪,有没有很眼熟,是上一章的最后一节我们说到的解析所有的Mapper配置
在解析的过程里,会把MappedStatement的id属性作为key,MappedStatement作为值放入到mappedStatements中

在这里插入图片描述
ps: 查看调用关系快捷键 Ctrl + Alt + H
在这里插入图片描述

2.3 Executor

我们通过调用栈来看下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);
      //通过configuration创建一个Executor
      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();
    }
  }

  private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) {
    try {
      boolean autoCommit;
      try {
        autoCommit = connection.getAutoCommit();
      } catch (SQLException e) {
        // Failover to true, as most poor drivers
        // or databases won't support transactions
        autoCommit = true;
      }
      final Environment environment = configuration.getEnvironment();
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      final Transaction tx = transactionFactory.newTransaction(connection);
      //通过configuration创建一个Executor
      final Executor executor = configuration.newExecutor(tx, execType);
      return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

public Executor newExecutor(Transaction transaction, ExecutorType executorType)代码

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
	//为空返回默认的executorType  ExecutorType.SIMPLE
    executorType = executorType == null ? defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    Executor executor;
    //根据不同类型返回不同的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);
    }
    //如果开启缓存,用缓存执行器对原始执行器进行包装,返回一个带缓存功能的执行器
    //默认是开启缓存的
    if (cacheEnabled) {
      executor = new CachingExecutor(executor);
    }
    //为所有的执行链加入当前的执行器插件
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
}

interceptorChain.pluginAll(executor)

public Object pluginAll(Object target) {
    for (Interceptor interceptor : interceptors) {
      target = interceptor.plugin(target);
    }
    return target;
}

interceptor.plugin(target)

default Object plugin(Object target) {
    return Plugin.wrap(target, this);
}

Plugin.wrap(target, this)

public static Object wrap(Object target, Interceptor interceptor) {
	//获取当前的interceptor上的注解中定义的Signature[],把需要代理的类和方法放入Map中
    Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
    Class<?> type = target.getClass();
    //匹配当前类有没有需要被代理的接口,有则返回代理对象,无返回原对象
    Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
    if (interfaces.length > 0) {
      return Proxy.newProxyInstance(
          type.getClassLoader(),
          interfaces,
          new Plugin(target, interceptor, signatureMap));
    }
    return target;
}

MyInterceptor和PageInterceptor类上的@Intercepts注解
此处定义的都是对Executor类的下面两个方法进行代理
query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql)
query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler)

在这里插入图片描述
最后代理两次后返回的Executor类
在这里插入图片描述

3. SqlSessionManager源码详解

3.1 私有的构造方法

  //内部的SqlSessionFactory,为实现SqlSessionFactory相关接口而使用
  private final SqlSessionFactory sqlSessionFactory;
  //内部的SqlSession代理类,为实现SqlSession相关接口而使用
  private final SqlSession sqlSessionProxy;
  //ThreadLocal<SqlSession> 事务相关等方法操作是使用
  private final ThreadLocal<SqlSession> localSqlSession = new ThreadLocal<>();

  //私有构造函数
  private SqlSessionManager(SqlSessionFactory sqlSessionFactory) {
    this.sqlSessionFactory = sqlSessionFactory;
    this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(
        SqlSessionFactory.class.getClassLoader(),
        new Class[]{SqlSession.class},
        new SqlSessionInterceptor());
  }

3.2 SqlSession的代理类SqlSessionInterceptor

private class SqlSessionInterceptor implements InvocationHandler {
    public SqlSessionInterceptor() {
        // Prevent Synthetic Access
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      //从LocalThread中获取SqlSession
      final SqlSession sqlSession = SqlSessionManager.this.localSqlSession.get();
      if (sqlSession != null) {
      	//LocalThread中有SqlSession,则使用
        try {
          return method.invoke(sqlSession, args);
        } catch (Throwable t) {
          throw ExceptionUtil.unwrapThrowable(t);
        }
      } else {
        //LocalThread中无SqlSession,获取一个SqlSession
        try (SqlSession autoSqlSession = openSession()) {
          try {
            final Object result = method.invoke(autoSqlSession, args);
            //手动提交
            autoSqlSession.commit();
            return result;
          } catch (Throwable t) {
          	//手动回滚
            autoSqlSession.rollback();
            throw ExceptionUtil.unwrapThrowable(t);
          }
        }
      }
    }
}

3.3 其他事务等方法

以下方法都是通过LocalThread中的SqlSession进行操作的

@Override
  public void clearCache() {
    final SqlSession sqlSession = localSqlSession.get();
    if (sqlSession == null) {
      throw new SqlSessionException("Error:  Cannot clear the cache.  No managed session is started.");
    }
    sqlSession.clearCache();
  }

  @Override
  public void commit() {
    final SqlSession sqlSession = localSqlSession.get();
    if (sqlSession == null) {
      throw new SqlSessionException("Error:  Cannot commit.  No managed session is started.");
    }
    sqlSession.commit();
  }

  @Override
  public void commit(boolean force) {
    final SqlSession sqlSession = localSqlSession.get();
    if (sqlSession == null) {
      throw new SqlSessionException("Error:  Cannot commit.  No managed session is started.");
    }
    sqlSession.commit(force);
  }

  @Override
  public void rollback() {
    final SqlSession sqlSession = localSqlSession.get();
    if (sqlSession == null) {
      throw new SqlSessionException("Error:  Cannot rollback.  No managed session is started.");
    }
    sqlSession.rollback();
  }

  @Override
  public void rollback(boolean force) {
    final SqlSession sqlSession = localSqlSession.get();
    if (sqlSession == null) {
      throw new SqlSessionException("Error:  Cannot rollback.  No managed session is started.");
    }
    sqlSession.rollback(force);
  }

  @Override
  public List<BatchResult> flushStatements() {
    final SqlSession sqlSession = localSqlSession.get();
    if (sqlSession == null) {
      throw new SqlSessionException("Error:  Cannot rollback.  No managed session is started.");
    }
    return sqlSession.flushStatements();
  }

  @Override
  public void close() {
    final SqlSession sqlSession = localSqlSession.get();
    if (sqlSession == null) {
      throw new SqlSessionException("Error:  Cannot close.  No managed session is started.");
    }
    try {
      sqlSession.close();
    } finally {
      localSqlSession.set(null);
    }
  }

总结

SqlSession的两个实现类DefaultSqlSessionSqlSessionManager.SqlSessionManager是通过DefaultSqlSession实现功能的.而DefaultSqlSession是通过内部的Executor实现的.后续章节我们再对Executor相关的代码进行详细的学习

喜欢的小伙伴请动动小手关注和点赞吧,也可留言一起探讨怎样更好的学习源码!!!

文章链接

Mybatis源码学习(一)初探执行流程
Mybatis源码学习(二)配置文件解析到SqlSessionFactory构建
Mybatis源码学习(三)SqlSession详解
Mybatis源码学习(四)自定义Mapper方法执行流程
Mybatis源码学习(五)Executor和StatementHandler详解
Mybatis源码学习(六)结果集自动封装机制
Mybatis源码学习(七)mybatis缓存详解
Mybatis源码学习(八)Mybatis设计模式总结

学习资料整理

本人作为Java开发菜鸡,平时也收集了很多学习视频,在此分享给大家一起学习

整套VIP学习视频

在这里插入图片描述

架构师相关视频

在这里插入图片描述

扫码领取

在这里插入图片描述

更多资料链接

Java免费学习视频下载
Python免费学习视频下载
Web前端免费学习视频下载
人工智能免费学习视频下载
大数据免费学习视频下载
UI设计免费学习视频下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值