MyBatis源码解析--加载流程(11)

Mybatis源码解析之执行流程解析 Mybatis源码解析之核心类分析 Mybatis源码解析之初始化分析 本篇文章将在前两篇文章的基础上解析Mybatis执行sql的流程。 一、 映射集mappers解析 对于在原生mybatis中的sql执行,需要在配置文件中通过标签引入mapper.xml文件。前文已经提到,对于xml配置文件,mybatis在XMLConfigBuilder#parseConfiguration(Xnode)... 阅读详情

接下来分析接口层,首先从SqlSession接口开始:

public interface SqlSession extends Closeable {
  //泛型方法,经过查询返回一个指定的对象
  <T> T selectOne(String statement);
  //根据传入的条件查询结果
  <T> T selectOne(String statement, Object parameter);

  //经过查询,返回泛型集合
  <E> List<E> selectList(String statement);
  //根据条件经过查询,返回泛型集合
  <E> List<E> selectList(String statement, Object parameter);
   //根据条件经过查询,返回泛型集合,rowBounds用于分页
  <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds);
  //经过查询,返回map
  <K, V> Map<K, V> selectMap(String statement, String mapKey);
   //根据条件经过查询,返回泛型集合
  <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey);

  //根据条件经过查询,返回泛型集合,rowBounds用于分页
  <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds);

  //返回值是游标对象
  <T> Cursor<T> selectCursor(String statement);

  <T> Cursor<T> selectCursor(String statement, Object parameter);

  <T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds);

  //查询结果的对象由指定的ResultHandler对象处理
  void select(String statement, Object parameter, ResultHandler handler);

  void select(String statement, ResultHandler handler);

  void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler);

  //执行insert语句
  int insert(String statement);
   
  int insert(String statement, Object parameter);
  //执行update语句
  int update(String statement);
  int update(String statement, Object parameter);

   //执行delete语句
  int delete(String statement);

  int delete(String statement, Object parameter);

  //提交事务
  void commit();

  void commit(boolean force);

  //回滚事务
  void rollback();

  void rollback(boolean force);

  //将请求刷新到数据库
  List<BatchResult> flushStatements();

  //关闭连接
  void close();

  //清空缓存
  void clearCache();

  //获取configuration对象
  Configuration getConfiguration();

  //根据mapper接口获取接口对应的动态代理实现
  <T> T getMapper(Class<T> type);

  //获取session对应的真实的数据库连接
  Connection getConnection();
}

DefaultSqlSession 接口的默认实现也是最常用的实现

public class DefaultSqlSession implements SqlSession {

  private final Configuration configuration;//configuration对象,全局唯一
  private final Executor executor;//底层依赖的excutor对象

  private final boolean autoCommit;//是否自动提交事务
  private boolean dirty;//当前缓存是否有脏数据
  //为了防止忘记关闭游标对象,会将生成的游标对象保存在这个list中,最后一起关闭
  private List<Cursor<?>> cursorList;
//构造函数
  public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
    this.configuration = configuration;
    this.executor = executor;
    this.dirty = false;
    this.autoCommit = autoCommit;
  }

  public DefaultSqlSession(Configuration configuration, Executor executor) {
    this(configuration, executor, false);
  }

  @Override
  public <T> T selectOne(String statement) {
    return this.<T>selectOne(statement, null);
  }

  @Override
  public <T> T selectOne(String statement, Object parameter) {
  //内部调用的是selectList方法
    List<T> list = this.<T>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;
    }
  }

  @Override
  public <K, V> Map<K, V> selectMap(String statement, String mapKey) {
    return this.selectMap(statement, null, mapKey, RowBounds.DEFAULT);
  }

  @Override
  public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) {
    return this.selectMap(statement, parameter, mapKey, RowBounds.DEFAULT);
  }

  @Override
  public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
  //执行查询
    final List<? extends V> list = selectList(statement, parameter, rowBounds);
    //创建 DefaultMapResultHandler 对象
    final DefaultMapResultHandler<K, V> mapResultHandler = new DefaultMapResultHandler<>(mapKey,
            configuration.getObjectFactory(), configuration.getObjectWrapperFactory(), configuration.getReflectorFactory());
    //创建 DefaultResultContext 对象
    final DefaultResultContext<V> context = new DefaultResultContext<>();
    //遍历查询结果
    for (V o : list) {
    //设置DefaultResultContext中
      context.nextResultObject(o);
      // 使用 DefaultMapResultHandler 处理结果的当前元素
      mapResultHandler.handleResult(context);
    }
    //返回结果
    return mapResultHandler.getMappedResults();
  }

  @Override
  public <T> Cursor<T> selectCursor(String statement) {
    return selectCursor(statement, null);
  }

  @Override
  public <T> Cursor<T> selectCursor(String statement, Object parameter) {
    return selectCursor(statement, parameter, RowBounds.DEFAULT);
  }

  @Override
  public <T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds) {
    try {
    //获得MappedStatement对象
      MappedStatement ms = configuration.getMappedStatement(statement);
      //执行查询
      Cursor<T> cursor = executor.queryCursor(ms, wrapCollection(parameter), rowBounds);
      //添加cursor到cursorList中
      registerCursor(cursor);
      return cursor;
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

  @Override
  public <E> List<E> selectList(String statement) {
    return this.selectList(statement, null);
  }

  @Override
  public <E> List<E> selectList(String statement, Object parameter) {
    return this.selectList(statement, parameter, RowBounds.DEFAULT);
  }

  @Override
  public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
      //从configuration中获取要执行的sql语句的配置信息
      MappedStatement ms = configuration.getMappedStatement(statement);
      //通过executor执行语句,并返回指定的结果集
      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();
    }
  }

  @Override
  public void select(String statement, Object parameter, ResultHandler handler) {
    select(statement, parameter, RowBounds.DEFAULT, handler);
  }

  @Override
  public void select(String statement, ResultHandler handler) {
    select(statement, null, RowBounds.DEFAULT, handler);
  }

  @Override
  public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
    try {
    //获得MappedStatement对象
      MappedStatement ms = configuration.getMappedStatement(statement);
      //执行查询
      executor.query(ms, wrapCollection(parameter), rowBounds, handler);
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

  @Override
  public int insert(String statement) {
    return insert(statement, null);
  }

  @Override
  public int insert(String statement, Object parameter) {
    return update(statement, parameter);
  }

  @Override
  public int update(String statement) {
    return update(statement, null);
  }

  @Override
  public int update(String statement, Object parameter) {
    try {
    //标记dirty,表示执行过写操作
      dirty = true;
      //获得MappedStatement对象
      MappedStatement ms = configuration.getMappedStatement(statement);
      //执行更新操作
      return executor.update(ms, wrapCollection(parameter));
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error updating database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

  @Override
  public int delete(String statement) {
    return update(statement, null);
  }

  @Override
  public int delete(String statement, Object parameter) {
    return update(statement, parameter);
  }

  @Override
  public void commit() {
    commit(false);
  }

  @Override
  public void commit(boolean force) {
    try {
    //提交事务
      executor.commit(isCommitOrRollbackRequired(force));
      //标记dirty为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);
  }

  @Override
  public void rollback(boolean force) {
    try {
    //回滚事务
      executor.rollback(isCommitOrRollbackRequired(force));
      //标记dirty为false
      dirty = false;
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error rolling back transaction.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

  @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();
    }
  }

  @Override
  public void close() {
    try {
    //关闭执行器
      executor.close(isCommitOrRollbackRequired(false));
      //关闭所有游标
      closeCursors();
      dirty = false;
    } finally {
      ErrorContext.instance().reset();
    }
  }

  private void closeCursors() {
    if (cursorList != null && cursorList.size() != 0) {
    //遍历cursorList中的游标,将其全部关闭
      for (Cursor<?> cursor : cursorList) {
        try {
          cursor.close();
        } catch (IOException e) {
          throw ExceptionFactory.wrapException("Error closing cursor.  Cause: " + e, e);
        }
      }
      cursorList.clear();
    }
  }

  @Override
  public Configuration getConfiguration() {
    return configuration;
  }

  @Override
  public <T> T getMapper(Class<T> type) {
    return configuration.<T>getMapper(type, this);
  }

  @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();
  }

  private <T> void registerCursor(Cursor<T> cursor) {
    if (cursorList == null) {
      cursorList = new ArrayList<>();
    }
    cursorList.add(cursor);
  }
//是否提交回滚事务
  private boolean isCommitOrRollbackRequired(boolean force) {
  //强制提交或者不是自动提交并且有脏数据
    return (!autoCommit && dirty) || force;
  }
//如果参数是Collection、Array、Map参数类型的情况下包装成Map返回
  private Object wrapCollection(final Object object) {
    if (object instanceof Collection) {
    //如果是集合,则添加到collection中
      StrictMap<Object> map = new StrictMap<>();
      map.put("collection", object);
      //如果是List,则添加到list中
      if (object instanceof List) {
        map.put("list", object);
      }
      return map;
    } else if (object != null && object.getClass().isArray()) {
    //如果是Array,则添加到array中
      StrictMap<Object> map = new StrictMap<>();
      map.put("array", object);
      return map;
    }
    return object;
  }

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

  }

}

SqlSessionFactory

public interface SqlSessionFactory {
//开启session的各种重载方法
  SqlSession openSession();

  SqlSession openSession(boolean autoCommit);
  SqlSession openSession(Connection connection);
  SqlSession openSession(TransactionIsolationLevel level);

  SqlSession openSession(ExecutorType execType);
  SqlSession openSession(ExecutorType execType, boolean autoCommit);
  SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
  SqlSession openSession(ExecutorType execType, Connection connection);

  Configuration getConfiguration();

}

DefaultSqlSessionFactory 默认的SqlSessionFactory实现类

public class DefaultSqlSessionFactory implements SqlSessionFactory {

  private final Configuration configuration;

  public DefaultSqlSessionFactory(Configuration configuration) {
    this.configuration = configuration;
  }

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

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

  @Override
  public SqlSession openSession(ExecutorType execType) {
    return openSessionFromDataSource(execType, null, false);
  }

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

  @Override
  public SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level) {
    return openSessionFromDataSource(execType, level, false);
  }

  @Override
  public SqlSession openSession(ExecutorType execType, boolean autoCommit) {
    return openSessionFromDataSource(execType, null, autoCommit);
  }

  @Override
  public SqlSession openSession(Connection connection) {
    return openSessionFromConnection(configuration.getDefaultExecutorType(), connection);
  }

  @Override
  public SqlSession openSession(ExecutorType execType, Connection connection) {
    return openSessionFromConnection(execType, connection);
  }

  @Override
  public Configuration getConfiguration() {
    return configuration;
  }

  //从数据源获取数据库连接
  private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
    	//获取mybatis配置文件中的environment对象
      final Environment environment = configuration.getEnvironment();
      //从environment获取transactionFactory对象
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      //创建事务对象
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      //根据配置创建executor
      final Executor executor = configuration.newExecutor(tx, execType);
      //创建DefaultSqlSession
      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();
    }
  }

  //从数据库连接获取sqlSession
  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;
      }
      //获取mybatis配置文件中的environment对象
      final Environment environment = configuration.getEnvironment();
      //从environment获取transactionFactory对象
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      //创建事务对象
      final Transaction tx = transactionFactory.newTransaction(connection);
      //根据配置创建executor
      final Executor executor = configuration.newExecutor(tx, execType);
      //创建DefaultSqlSession
      return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

  private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
  //情况一创建ManagedTransactionFactory对象
    if (environment == null || environment.getTransactionFactory() == null) {
      return new ManagedTransactionFactory();
    }
    //情况二使用environment中的
    return environment.getTransactionFactory();
  }

  private void closeTransaction(Transaction tx) {
    if (tx != null) {
      try {
        tx.close();
      } catch (SQLException ignore) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }

}

SqlSessionManager 实现了SqlSessionFactory、SqlSession接口,SqlSession管理器,因此SqlSessionManager是SqlSessionFactory和SqlSession的职能相加。

public class SqlSessionManager implements SqlSessionFactory, SqlSession {

  //底层封装的
  private final SqlSessionFactory sqlSessionFactory;
  private final SqlSession sqlSessionProxy;

  private final ThreadLocal<SqlSession> localSqlSession = new ThreadLocal<>();
//私有的构造方法
  private SqlSessionManager(SqlSessionFactory sqlSessionFactory) {
    this.sqlSessionFactory = sqlSessionFactory;
    //创建SqlSession的代理对象
    this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(
        SqlSessionFactory.class.getClassLoader(),
        new Class[]{SqlSession.class},
        new SqlSessionInterceptor());
  }

  public static SqlSessionManager newInstance(Reader reader) {
    return new SqlSessionManager(new SqlSessionFactoryBuilder().build(reader, null, null));
  }

  public static SqlSessionManager newInstance(Reader reader, String environment) {
    return new SqlSessionManager(new SqlSessionFactoryBuilder().build(reader, environment, null));
  }

  public static SqlSessionManager newInstance(Reader reader, Properties properties) {
    return new SqlSessionManager(new SqlSessionFactoryBuilder().build(reader, null, properties));
  }

  public static SqlSessionManager newInstance(InputStream inputStream) {
    return new SqlSessionManager(new SqlSessionFactoryBuilder().build(inputStream, null, null));
  }

  public static SqlSessionManager newInstance(InputStream inputStream, String environment) {
    return new SqlSessionManager(new SqlSessionFactoryBuilder().build(inputStream, environment, null));
  }

  public static SqlSessionManager newInstance(InputStream inputStream, Properties properties) {
    return new SqlSessionManager(new SqlSessionFactoryBuilder().build(inputStream, null, properties));
  }

  public static SqlSessionManager newInstance(SqlSessionFactory sqlSessionFactory) {
    return new SqlSessionManager(sqlSessionFactory);
  }
//发起一个可以被管理的SqlSession
  public void startManagedSession() {
    this.localSqlSession.set(openSession());
  }

  public void startManagedSession(boolean autoCommit) {
    this.localSqlSession.set(openSession(autoCommit));
  }

  public void startManagedSession(Connection connection) {
    this.localSqlSession.set(openSession(connection));
  }

  public void startManagedSession(TransactionIsolationLevel level) {
    this.localSqlSession.set(openSession(level));
  }

  public void startManagedSession(ExecutorType execType) {
    this.localSqlSession.set(openSession(execType));
  }

  public void startManagedSession(ExecutorType execType, boolean autoCommit) {
    this.localSqlSession.set(openSession(execType, autoCommit));
  }

  public void startManagedSession(ExecutorType execType, TransactionIsolationLevel level) {
    this.localSqlSession.set(openSession(execType, level));
  }

  public void startManagedSession(ExecutorType execType, Connection connection) {
    this.localSqlSession.set(openSession(execType, connection));
  }

  public boolean isManagedSessionStarted() {
    return this.localSqlSession.get() != null;
  }

  @Override
  //直接调用sqlSessionFactory的openSession
  public SqlSession openSession() {
    return sqlSessionFactory.openSession();
  }

  @Override
  public SqlSession openSession(boolean autoCommit) {
    return sqlSessionFactory.openSession(autoCommit);
  }

  @Override
  public SqlSession openSession(Connection connection) {
    return sqlSessionFactory.openSession(connection);
  }

  @Override
  public SqlSession openSession(TransactionIsolationLevel level) {
    return sqlSessionFactory.openSession(level);
  }

  @Override
  public SqlSession openSession(ExecutorType execType) {
    return sqlSessionFactory.openSession(execType);
  }

  @Override
  public SqlSession openSession(ExecutorType execType, boolean autoCommit) {
    return sqlSessionFactory.openSession(execType, autoCommit);
  }

  @Override
  public SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level) {
    return sqlSessionFactory.openSession(execType, level);
  }

  @Override
  public SqlSession openSession(ExecutorType execType, Connection connection) {
    return sqlSessionFactory.openSession(execType, connection);
  }

  @Override
  public Configuration getConfiguration() {
    return sqlSessionFactory.getConfiguration();
  }
//都是通过sqlSession的代理对象来实现
  @Override
  public <T> T selectOne(String statement) {
    return sqlSessionProxy.<T> selectOne(statement);
  }

  @Override
  public <T> T selectOne(String statement, Object parameter) {
    return sqlSessionProxy.<T> selectOne(statement, parameter);
  }

  @Override
  public <K, V> Map<K, V> selectMap(String statement, String mapKey) {
    return sqlSessionProxy.<K, V> selectMap(statement, mapKey);
  }

  @Override
  public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) {
    return sqlSessionProxy.<K, V> selectMap(statement, parameter, mapKey);
  }

  @Override
  public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
    return sqlSessionProxy.<K, V> selectMap(statement, parameter, mapKey, rowBounds);
  }

  @Override
  public <T> Cursor<T> selectCursor(String statement) {
    return sqlSessionProxy.selectCursor(statement);
  }

  @Override
  public <T> Cursor<T> selectCursor(String statement, Object parameter) {
    return sqlSessionProxy.selectCursor(statement, parameter);
  }

  @Override
  public <T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds) {
    return sqlSessionProxy.selectCursor(statement, parameter, rowBounds);
  }

  @Override
  public <E> List<E> selectList(String statement) {
    return sqlSessionProxy.<E> selectList(statement);
  }

  @Override
  public <E> List<E> selectList(String statement, Object parameter) {
    return sqlSessionProxy.<E> selectList(statement, parameter);
  }

  @Override
  public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    return sqlSessionProxy.<E> selectList(statement, parameter, rowBounds);
  }

  @Override
  public void select(String statement, ResultHandler handler) {
    sqlSessionProxy.select(statement, handler);
  }

  @Override
  public void select(String statement, Object parameter, ResultHandler handler) {
    sqlSessionProxy.select(statement, parameter, handler);
  }

  @Override
  public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
    sqlSessionProxy.select(statement, parameter, rowBounds, handler);
  }

  @Override
  public int insert(String statement) {
    return sqlSessionProxy.insert(statement);
  }

  @Override
  public int insert(String statement, Object parameter) {
    return sqlSessionProxy.insert(statement, parameter);
  }

  @Override
  public int update(String statement) {
    return sqlSessionProxy.update(statement);
  }

  @Override
  public int update(String statement, Object parameter) {
    return sqlSessionProxy.update(statement, parameter);
  }

  @Override
  public int delete(String statement) {
    return sqlSessionProxy.delete(statement);
  }

  @Override
  public int delete(String statement, Object parameter) {
    return sqlSessionProxy.delete(statement, parameter);
  }

  @Override
  public <T> T getMapper(Class<T> type) {
    return getConfiguration().getMapper(type, this);
  }

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

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

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    //如果localSqlSession 中存在 SqlSession 对象,说明是自管理模式
      final SqlSession sqlSession = SqlSessionManager.this.localSqlSession.get();
      if (sqlSession != null) {
        try {
        //直接执行方法
          return method.invoke(sqlSession, args);
        } catch (Throwable t) {
          throw ExceptionUtil.unwrapThrowable(t);
        }
        //如果没有SqlSession对象,则直接创建一个
      } else {
        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);
          }
        }
      }
    }
  }

}

MyBatis源码剖析 在二级缓存的设计上,MyBatis大量的运用了装饰者模式,如CacheExecutor,以及各种Cache接口的装饰器。二级缓存实现了sqlSession之间的缓存数据共享,属于namespace级别;二级缓存具有丰富的缓存策略;二级缓存可由多个装饰器与基础缓存组合而成;二级缓存工作由一个缓存装饰器CacheExecutor和一个事务型预缓存TransactionalCache完成。问题:在开发过程中很多时候我们并不总是需要在获取用户信息的时候加载订单信息,此时就是我们所说的延迟加载。 阅读详情

相关推荐

深入解析MyBatis源码与实战

摘要:本文系统解析MyBatis核心架构与实现原理,涵盖配置解析、SQL执行、结果映射三大模块。通过动态SQL生成、缓存机制(一级/二级缓存)、插件开发(Interceptor接口)等典型示例,深入剖析源码实现。结合SpringBoot集成场景,展示CRUD操作、动态SQL拼接、事务管理、多数据源配置等实战方案,并给出批量操作优化(BatchExecutor)、类型处理器扩展等高级特性实现。特别说明流程图关键节点:从SqlSessionFactory构建到Executor执行,通过StatementHand

keny-大成的博客 1371

mybatis源码解读(3)

selectOne和selectListString resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build

Erik 1154

再生龙(clonezilla)镜像比目标盘大——基于centos8.5

再生龙恢复到小盘遇到的问题及处理,首先是修改分区大小,进入dracut模式后再尝试恢复临时系统。

u010101453的博客 3690

Mybatis源码分析-selectList源码分析

文章目录一、开篇二、源码分析1.selectList()2.CachingExecutor3、createCacheKey1)为什么CachingExecutor要调用SimpleExecutor的方法去创建缓存key呢?4、创建好缓存key之后:query查询二级缓存5、如果二级缓存为空继续走查询query查询一级缓存6、查询一级缓存为空queryFromDatabase查询数据库三、演示四、总结 一、开篇 在我们分析Executor的时候最后一步就是查询我们的数据库 本篇就是去深究一下Mybatis

瑞文のBlog 1916

避坑指南:STM32H7不同DMA控制器(MDMA/DMA2D/BDMA)到底该用哪个?

本文深入解析STM32H7系列芯片的DMA控制器选型策略,涵盖MDMA、DMA2D、BDMA等不同控制器的架构原理与性能对比。通过实际项目案例,提供高速TCM数据搬运、GUI加速、低功耗传输等场景的选型决策树,并分享性能优化与调试技巧,帮助工程师避开常见陷阱,提升系统效率。

weixin_26876073的博客 448

Android开发中StateFlow与LiveData的5个关键区别及实战避坑指南

本文深度解析了Android开发中StateFlow与LiveData的5个核心区别,包括设计哲学、生命周期管理、值更新策略、线程模型及协程生态整合。通过实战代码对比,为开发者在现代MVVM架构下的状态管理选型提供清晰的决策指南和避坑建议,帮助构建更健壮、可测试的应用。

weixin_29012677的博客 405

Mybatis源码阅读(五 ):接口层——SqlSession

SqlSession SqlSession是Mybatis的核心接口之一,对外提供常用的数据库操作api。mybatis提供了两个SqlSession的实现,其中最常用的是DefaultSqlSession。 SqlSession的代码如下 /** * 接口层,也是开发人员使用mybatis去操作sql所使用的主要的接口 * * @author Clinton Begin */ public interface SqlSession extends Closeable { /**

qq_36403693的博客 650

用Linkboy玩转Arduino:3小时搞定智能倒车雷达(附仿真文件下载)

本文详细介绍了如何利用Linkboy图形化编程工具,在3小时内快速搭建一个基于Arduino的智能倒车雷达项目。通过仿真环境,初学者无需硬件即可学习超声波测距原理、报警逻辑设计,并完成从虚拟仿真到实体硬件的完整流程。文章提供了清晰的步骤、调试技巧及功能扩展思路,并附有仿真文件,是入门Arduino和智能硬件制作的绝佳实践指南。

weixin_29159441的博客 404

架构师进阶之路——1、持久化框架(二)

目录 一、Mybatis源码剖析 1、传统方式源码剖析 1)初始化 2)执行SQL流程 3)executor 4)、StatementHandler 2、 Mapper代理方式 一、Mybatis源码剖析 1、传统方式源码剖析 1)初始化 Inputstream inputstream = Resources.getResourceAsStream("mybatis- config.xml"); //这一行代码正是初始化工作的开始。 SqlSessionFactory fac..

moxiaolin的博客 365

AI时代敏捷开发新范式——意图驱动开发IDD

具体的功能代码、单元测试、集成测试用例,以及最终可运行的、支持PlantUML的Markdown转Word工具新版本。:业务方(如技术文档团队)反馈,现有的Markdown转Word工具在处理包含PlantUML代码块的文档时,无法正确生成图表,导致技术方案、架构图等关键信息丢失,严重影响了文档交付质量和团队效率。这不仅带来了交付周期显著缩短、资源效能倍增的可观收益,更深远的意义在于,它描绘了未来软件工业化、智能化的新图景:一个由精准意图驱动、AI自主执行、人类智慧引领的敏捷、高效、高质的新世界。

LiuJunjiang的专栏 557

Vue3 - Element Plus上传组件el-upload上传多个文件时,让on-change监听事件仅执行一次并获取最终文件列表方法(开启多选文件并手动上传,拿到文件列表统一循环调用接口上传)

vue3,elementplus,Upload上传,el-upload,文件上传组件,上传组件on-change里执行多次,取消自动上传后change重复执行问题,upload上传多个文件后导致on-change执行多次拿不到最终文件列表,Element-plus的upload组件on-change不断执行怎么办,上传多个文件多次执行调用,上传多个文件时如何只执行一次on-change方法拿到最终的文件列表,vue3elementplus上传组件开启多个上传后导致change方法执行好几次,仅调用一

🏆 前端领域优质创作者 1万+

mybaitis之select

//DefaultSqlSession @Override public List selectList(String statement, Object parameter) { //statement:namespace+id //parameter:传递的参数,如对象 list 、map、pojo 等 //RowBounds.DEFAULT 逻辑分页 在DefaultResultHandl...

weixin_43189882的博客 281

基于RAG(Retrieval Augmented Generation)架构的简单问答系统的Python实现示例

以下是一个基于RAG(Retrieval Augmented Generation)架构的简单问答系统的Python实现示例。这个系统使用langchain库进行文档处理、检索,以及与大语言模型交互。

max500600的博客 743

Mybatis-plus源码解读-自动装配与加载流程

本文分析了MyBatis-Plus的核心自动装配机制,重点介绍了MybatisPlusAutoConfiguration作为SpringBoot集成入口的关键作用。通过MybatisSqlSessionFactoryBuilder构建支持MyBatis-Plus特性的SqlSessionFactory,并详细解析了MybatisConfiguration、MybatisMapperRegistry等核心组件的扩展实现。文章还阐述了ISqlInjector接口及其实现类如何动态注入BaseMapper的CRU

源码老人的专栏 2038

RK3588 实战级 YOLOv5 Android 全解析:NPU 量化 + 多线程 + 跟踪算法,源码一次买齐

本文将带你完成一个完整的AI视觉项目:在搭载RK3588芯片的Android开发板上运行实时目标检测与跟踪应用。实战目标:成功运行官方YOLOV5摄像头实时检测案例技术深度:深入理解RKNN开发框架和源码实现核心技能:掌握NPU推理、多线程并发、目标跟踪等关键技术。

FJN110的博客 157

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

mybatis的执行流程

mybatis的执行流程如下代码: 第一步:通过Resources加载配置好的mybatis.xml配置文件。 Resources是ibatis.io包下面的类,也就是一个io流,用于读写文件,通过getResourceAsStream把xml文件加载进来,把配置文件解析为一个流。   第二步:然后看第二句话,这句话是关键。我们首先new了一个SqlSessionFactoryBuil...

落叶飘零z的博客 4万+

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

MyBatis源码剖析之延迟加载源码细节

在开发过程中很多时候我们并不需要总是在加载⽤户信息时就⼀定要加载他的订单信息。此时就是我们所说的延迟加载。举个栗⼦:在⼀对多中,当我们有⼀个⽤户,它有个100个订单在查询⽤户的时候,要不要把关联的订单查出来?在查询订单的时候,要不要把关联的⽤户查出来?回答在查询⽤户时,⽤户下的订单应该是,什么时候⽤,什么时候查询。在查询订单时,订单所属的⽤户信息应该是随着订单⼀起查询出来。延迟加载就是在需要⽤到数据时才进⾏加载,不需要⽤到数据时就不加载数据。延迟加载也称懒加载。

write less , do more 3334

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

Mybatis源码解读-Configuration 配置信息加载流程源码分析

mybatis启动流程分析,解读源码如何从加载mybatis-config.xml配置到执行流程; 1、mybatis-config.xml配置文件加载 2、配置节点与Configuration全局配置映射 3、解读配置信息加载相关类梳理

源码老人的专栏 921

Mybatis-SpringBoot源码解析之一:SqlSessionFactory加载流程

Mybatis-SpringBoot源码解析

zhengguofeng0328的博客 4179

Mybatis源码解析

mybatis的流程分析

WinnerBear的博客 5218

MyBatis源码解析--加载流程(1)

分析完11个提供支持的模块,接下来就完整地debug一遍加载的流程。 首先看下简单的流程: 1.初始化会加载mybatis-config.xml配置文件、mapper映射配置文件以及Mapper接口中的注解信息,这些信息都会形成相应的对象并保存到Configuration中。 2.利用Configuration创建SqlSessionFactory对象。 3.通过SqlSessionFactory创建SqlSession对象进行相关的数据库操作。 那么首先就从加载mybatis-config.xml文件开始

jacobbbbbbbb的博客 325

Mybatis源码解析之配置加载(一)

Mybatis源码解析之配置加载(一) 用了好几年的mybatis了,但是很少来钻研mybatis原理所在,最近抽出空来,就把这一整套源码都研究了下,然后发现就是这些东西,mybatis没啥难度,于是决定把研究的这一整套写一个mybatis系列,记录一下,在这些完了以后,顺便写一个小的mybatis框架。 1. demo演示 还是从用法开始吧,就不开始就从源码说了,mybatis的conf配置文...

u012734441的专栏 3712

MyBatis 源码解析:Mapper 文件加载与解析

`Mapper` 文件是 MyBatis 中连接 SQL 和 Java 对象的桥梁。本文将通过自定义实现一个简单的 Mapper 文件加载与解析器,展示其工作原理,并对比 MyBatis 中的 Mapper 文件解析过程,帮助读者理解 MyBatis 内部的 Mapper 文件加载与解析机制。

捕风捉你 · 星桥API接入与大模型实战 1795

mybatis源码解析(二)-加载过程

mybatis源码解析(一)-开篇 mybatis源码解析(二)-加载过程 mybatis源码解析(三)-SqlSession.selectOne类似方法调用过程 mybatis源码解析(四)-Mapper方法调用过程 mybatis源码解析(五)-mybatis如何实现的事务控制 mybatis源码解析(六)-配合spring-tx实现事务的原理 mybatis源码解析(七)-当my...

civil的专栏 5658

Mybatis源码之--XML完整解析流程

MyBatis源码解析(一) 如何编译源码 仓库地址 1、idea中打开项目 2、等待解析依赖 备注:解析依赖的过程中有可能某些jar包的版本找不到,可自行在https://mvnrepository.com/ 找寻替代版本 XML解析 mybatis3支持注解方式声明SQL语句,但是最终经过mybatis内部解析,作用和使用XML定义是一样的。 只要你理解了XML的整个解析流程,其实就已经吃透了mybatis。 在阅读源码的过程中,mybatis的中文官网必须时刻去翻阅。特别是如下几章内容: 入

twx843571091的博客 4575

MyBatis执行一条sql语句的流程(源码解析)

加载配置文件:通过类加载器ClassLoaderWrapper以及一些其他的类加载器加载mybatis配置文件获得输入流。SqlsessionFactory的创建。

m0_71338251的博客 1864
上一篇: MyBatis源码解析--加载流程(10)
下一篇: Spring整合Mybatis源码分析
jacobbbbbbbb
博客等级 码龄7年 6粉丝 66原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值