Files
logseq-1/pages/Mybatis源码.md
2024-06-17 22:24:52 +08:00

6.2 KiB
Raw Permalink Blame History

  • Mybatis初始化过程
    • 通过InputStream来获取配置文件
    • ClassLoaderWarpper中的getResourceAsStream可以根据配置的resoutce来获取到配置文件的输入六
    • 使用ClassLoader是因为类加载器可具有读取外部资源的能力
    • image.png
    • 读取到配置文件后传入SqlSessionFactoryBuilder内部使用XMLConfigBuilder的parse方法读取配置并set到一个configuration变量中返回一个Configuration对象
    • image.png
    • 使用build方法创建一个DefaultSqlSessionFactory并返回
    • 在其中会创建一个SqlSession其中会创建事务工厂之类的
    • image.png
    • 将mapper类传入session通过session.getMapper方法在mapperRegistry获取到一个该mapper类的代理类MapperProxy
    • 执行时会执行该代理类的invoke方法
    • image.png
    • 触发mapperMethod的execute方法
    • public Object execute(SqlSession sqlSession, Object[] args) {
        Object result;
        switch (command.getType()) {
          case *INSERT*: {
            Object param = method.convertArgsToSqlCommandParam(args);
            result = rowCountResult(sqlSession.insert(command.getName(), param));
            break;
          }
          case *UPDATE*: {
            Object param = method.convertArgsToSqlCommandParam(args);
            result = rowCountResult(sqlSession.update(command.getName(), param));
            break;
          }
          case *DELETE*: {
            Object param = method.convertArgsToSqlCommandParam(args);
            result = rowCountResult(sqlSession.delete(command.getName(), param));
            break;
          }
          case *SELECT*:
            if (method.returnsVoid() && method.hasResultHandler()) {
              executeWithResultHandler(sqlSession, args);
              result = null;
            } else if (method.returnsMany()) {
              result = executeForMany(sqlSession, args);
            } else if (method.returnsMap()) {
              result = executeForMap(sqlSession, args);
            } else if (method.returnsCursor()) {
              result = executeForCursor(sqlSession, args);
            } else {
              Object param = method.convertArgsToSqlCommandParam(args);
              result = sqlSession.selectOne(command.getName(), param);
              if (method.returnsOptional()
                  && (result == null || !method.getReturnType().equals(result.getClass()))) {
                result = Optional.*ofNullable*(result);
              }
            }
            break;
          case *FLUSH*:
            result = sqlSession.flushStatements();
            break;
          default:
            throw new BindingException("Unknown execution method for: " + command.getName());
        }
        if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
          throw new BindingException("Mapper method '" + command.getName()
              + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
        }
        return result;
      }
      
    • 会根据不同的语句类型执行不同的execute方法查询list会执行executeForMany方法
    • private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
        List<E> result;
        Object param = method.convertArgsToSqlCommandParam(args);
        if (method.hasRowBounds()) {
          RowBounds rowBounds = method.extractRowBounds(args);
          result = sqlSession.selectList(command.getName(), param, rowBounds);
        } else {
          result = sqlSession.selectList(command.getName(), param);
        }
        *// issue #510 Collections & arrays support
      *  if (!method.getReturnType().isAssignableFrom(result.getClass())) {
          if (method.getReturnType().isArray()) {
            return convertToArray(result);
          } else {
            return convertToDeclaredCollection(sqlSession.getConfiguration(), result);
          }
        }
        return result;
      }
      
    • selectList获取MappedStatement再执行executor.query方法
    • @Override
      public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
        BoundSql boundSql = ms.getBoundSql(parameterObject);
        CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
        return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
      }
      
    • BoundSql为去掉ifwhere标签的sql语句Cachekey为缓存key
    • 查询时先从缓存获取获取不到或list为null就执行delegate.query方法查询
    • 检查executor是否被关闭是否清理缓存
    • 通过queryFromDatabase先在缓存中放一个占位符接着使用doQuery方法查询然后把缓存中的占位符换成真正的结果
    • private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
        List<E> list;
        localCache.putObject(key, *EXECUTION_PLACEHOLDER*);
        try {
          list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
        } finally {
          localCache.removeObject(key);
        }
        localCache.putObject(key, list);
        if (ms.getStatementType() == StatementType.*CALLABLE*) {
          localOutputParameterCache.putObject(key, parameter);
        }
        return list;
      }
      
    • 执行doQuery方法为BatchExecutor类的方法
    • public <E> List<E> doQuery(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
          throws SQLException {
        Statement stmt = null;
        try {
          flushStatements();
          Configuration configuration = ms.getConfiguration();
          StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameterObject, rowBounds, resultHandler, boundSql);
          Connection connection = getConnection(ms.getStatementLog());
          stmt = handler.prepare(connection, transaction.getTimeout());
          handler.parameterize(stmt);
          return handler.query(stmt, resultHandler);
        } finally {
          closeStatement(stmt);
        }
      }
      
    • 通过Statement执行静态语句获取结果
    • 执行的是PrepareStatementHandler.query方法获取结果后交给ResultSetHandler处理通过resultMap将值赋值给对象