mybatis 查询原理

mybatis 所有操作都会通过 sqlSession 来完成

public interface SqlSession extends Closeable {
    <T> T selectOne(String var1);

    <T> T selectOne(String var1, Object var2);

    <E> List<E> selectList(String var1);

    <E> List<E> selectList(String var1, Object var2);

    <E> List<E> selectList(String var1, Object var2, RowBounds var3);

    <K, V> Map<K, V> selectMap(String var1, String var2);

    <K, V> Map<K, V> selectMap(String var1, Object var2, String var3);

    <K, V> Map<K, V> selectMap(String var1, Object var2, String var3, RowBounds var4);

    <T> Cursor<T> selectCursor(String var1);

    <T> Cursor<T> selectCursor(String var1, Object var2);

    <T> Cursor<T> selectCursor(String var1, Object var2, RowBounds var3);

    void select(String var1, Object var2, ResultHandler var3);

    void select(String var1, ResultHandler var2);

    void select(String var1, Object var2, RowBounds var3, ResultHandler var4);

    int insert(String var1);

    int insert(String var1, Object var2);

    int update(String var1);

    int update(String var1, Object var2);

    int delete(String var1);

    int delete(String var1, Object var2);

    void commit();

    void commit(boolean var1);

    void rollback();

    void rollback(boolean var1);

    List<BatchResult> flushStatements();

    void close();

    void clearCache();

    Configuration getConfiguration();

    <T> T getMapper(Class<T> var1);

    Connection getConnection();
}

  1. 获取 SqlSessionFactory(SqlSessionFactory 初始化)

    1. org.apache.ibatis.session.SqlSessionFactoryBuilder#build(java.io.InputStream),返回的是 DefaultSqlSessionFactory
    2. 里面再调用 parse 方法解析配置文件,构建一个 Configuration 对象(包括全局配置文件和mapper.xml映射文件)
      1. mapper 映射文件中的每个增删改查都会封装成一个 MappedStatement 对象,然后放到 mappedStatements里。mappedStatements 是一个 map,key 是 id,value 是 MappedStatement(configruation.mappedStatements
      2. 所有的 mapper 接口文件解析后的信息都放在 configruation.mapperRegistry 里。 mapperRegistry 里面还有个 knownMappers,这是一个 map 放着每个 mapper 接口和其代理对象的工厂对象,后面会根据这个创建 mapper 接口的代理对象(configruation.mapperRegistry.knownMappers
  2. 获取 SqlSession,里面包含了 Executor 和 Configuration

    1. org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSession(),返回的是 DefaultSqlSession

    2. org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSessionFromDataSource

      private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
              Transaction tx = null;
      
              DefaultSqlSession var8;
              try {
                  Environment environment = this.configuration.getEnvironment();
                  TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
                  tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
                  // 这个是关键,所有数据库操作都是 Executor 完成的
                  Executor executor = this.configuration.newExecutor(tx, execType);
                  var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
              } catch (Exception var12) {
                  Exception e = var12;
                  this.closeTransaction(tx);
                  throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
              } finally {
                  ErrorContext.instance().reset();
              }
      
              return var8;
          }
      
    3. org.apache.ibatis.session.Configuration#newExecutor(org.apache.ibatis.transaction.Transaction, org.apache.ibatis.session.ExecutorType)

      public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
              executorType = executorType == null ? this.defaultExecutorType : executorType;
              executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
              // 根据条件创建不同的 executor,默认是 Simple
              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);
              }
      		// 如果开启了缓存,再把 executor 包装一下,最终都是通过包装后的 executor 执行 db 操作
              if (this.cacheEnabled) {
                  executor = new CachingExecutor((Executor)executor);
              }
      		// 如果有插件,再包装一下,同上最终使用还是还是包装后的 executor
              Executor executor = (Executor)this.interceptorChain.pluginAll(executor);
              return executor;
          }
      
  3. getMapper 获取代理对象

    1. org.apache.ibatis.session.defaults.DefaultSqlSession#getMapper

      public <T> T getMapper(Class<T> type) {
      	return this.configuration.getMapper(type, this);
      }
      
    2. org.apache.ibatis.session.Configuration#getMapper

      public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
          // 刚才说了初始化 SqlSessionFactoryBuilder 的时候设置了 configruation.mapperRegistry 并维护了 knownMappers
          // 这里 getMapper 的就是调用 MapperRegistry 的方法
          return this.mapperRegistry.getMapper(type, sqlSession);
      }
      
    3. org.apache.ibatis.binding.MapperRegistry#getMapper

      public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
          MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
          if (mapperProxyFactory == null) {
              throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
          } else {
              try {
                  // 调用 newInstance 创建对象,这里就不继续点了
                  // 后面步骤也很清晰:通过JDK动态代理创建对象;代理对象里面含有 sqlSession(sqlSession 里面有 executor)
                  return mapperProxyFactory.newInstance(sqlSession);
              } catch (Exception var5) {
                  Exception e = var5;
                  throw new BindingException("Error getting mapper instance. Cause: " + e, e);
              }
          }
      }
      
  4. 根据 Mapper 获取到了对象,就该调用里面的方法了,比如 selectById,现根据方法名判断是否是 Object 的方法,比如 toString、equlas 等,不是 Object 的方法,就把当前方法包装成一个 MapperMethod,传入 SqlSession 来执行这个方法 mapperMethod.execute(this.sqlSession, args)

    public Object execute(SqlSession sqlSession, Object[] args) {
            Object result;
            Object param;
        	// command 有两个属性
        	// 属性1 String name:mapper xml 的 id,也就是 MappedStatement 的 id,也就是 mapper 接口的方法全限定名
        	// 属性2 SqlCommandType type:语句的类型,增删改成哪一种,是一个枚举
            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()) { // 返回 map 怎么执行
                        result = this.executeForMap(sqlSession, args);
                    } else if (this.method.returnsCursor()) { // 返回游标怎么执行
                        result = this.executeForCursor(sqlSession, args);
                    } else {
                        // 处理参数,如果只有一个参数直接返回,如果是多个就返回一个 map,param 里面都是参数信息
                        param = this.method.convertArgsToSqlCommandParam(args);
                        // 参数参数 sqlSession 方法并调用(底层还是会调用 sqlSession.selectList,返回第一个)
                        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;
            }
        }
    
  5. org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object, org.apache.ibatis.session.RowBounds)

    public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
        List var5;
        try {
            // 先拿到 MappedStatement,也就是 xml 定义的东西
            MappedStatement ms = this.configuration.getMappedStatement(statement);
            // MappedStatement 传给 executor 的 query 方法。this.wrapCollection(parameter):再次包装参数,集合,map,还是单个参数
            var5 = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
        } catch (Exception var9) {
            Exception e = var9;
            throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
        } finally {
            ErrorContext.instance().reset();
        }
    
        return var5;
    }
    
  6. org.apache.ibatis.executor.BaseExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler) 这个 query 做了什么

    public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    	// 这个里面是所有 sql 信息的对象,参数是什么,值是什么,语句是什么(boundSql.getSql能拿到真正执行的sql,这里调试比较有用)
        BoundSql boundSql = ms.getBoundSql(parameter);
        // 构建一个缓存 key,下面查询的时候用这个缓存 key 去查,有就返回,没有就查库
        CacheKey key = this.createCacheKey(ms, parameter, rowBounds, boundSql);
        // 再调用 query 方法
        return this.query(ms, parameter, rowBounds, resultHandler, key, boundSql);
    }
    
  7. org.apache.ibatis.executor.BaseExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

    public <E> List<E> 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()) {
                    DeferredLoad deferredLoad = (DeferredLoad)var8.next();
                    deferredLoad.load();
                }
    
                this.deferredLoads.clear();
                if (this.configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
                    this.clearLocalCache();
                }
            }
    
            return list;
        }
    }
    
  8. queryFromDatabase 方法又调用了 doQuery 方法org.apache.ibatis.executor.SimpleExecutor#doQuery

    public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        // java.sql 这个包下面的,再接近 jdbc 了
        Statement stmt = null;
    
        List var9;
        try {
            Configuration configuration = ms.getConfiguration();
            // 先创建 Statement 处理器
            StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
            // 根据 Statement 处理器拿到 Statement
            stmt = this.prepareStatement(handler, ms.getStatementLog());
            // 再把 Statement 传给 query
            var9 = handler.query(stmt, resultHandler);
        } finally {
            this.closeStatement(stmt);
        }
    
        return var9;
    }
    
  9. 然后参数处理,执行查询,结果映射,关闭连接等

posted @ 2024-07-01 15:27  CyrusHuang  阅读(2)  评论(0编辑  收藏  举报