美文网首页
Mybatis查询流程

Mybatis查询流程

作者: 夜色001 | 来源:发表于2019-12-12 16:08 被阅读0次
image.png

一、前提条件

Configuration
MapperStatement:服务启动时,从Mapper中读出MapperStatement并缓存到Configuration中。

protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection");

SqlSession
生成代理类MapperProxy时,需将提前生成的SqlSession传入MapperProxy。此处的SqlSession为mybatis-spring包提供的SqlSessionTemplate类,而不是DefaultSqlSession类。

public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
    this.sqlSession = sqlSession;
    this.mapperInterface = mapperInterface;
    this.methodCache = methodCache;
  }

二、MapperProxy代理dao接口

触发MapperProxy代理类的invoke方法,MapperProxy从methodCache中查找mapper对应的MapperMethod,并交由MapperMethod执行具体的方法。

private final Map<Method, MapperMethod> methodCache;

@Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      } else if (isDefaultMethod(method)) {
        return invokeDefaultMethod(proxy, method, args);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    return mapperMethod.execute(sqlSession, args);
  }

三、MapperMethod执行mapper方法

MapperMethod引用SqlSessionTemplate执行查询

public Object execute(SqlSession sqlSession, Object[] args) {
     ......
     result = executeForMany(sqlSession, args);
     ......
}

private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
    List<E> result;
    ......
    result = sqlSession.<E>selectList(command.getName(), param);
    ......
    return result;
  }

四、SqlSessionTemplate通过动态代理调用DefaultSqlSession执行查询

1、SqlSessionTemplate动态代理SqlSession
2、SqlSessionInterceptor实现InvocationHandler接口,当调用代理对象的接口selectList时,触发SqlSessionInterceptor的invoke方法。
3、SqlSessionInterceptor在invoke中通过DefaultSqlSession执行查询

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

this.sqlSessionProxy = (SqlSession) newProxyInstance(
        SqlSessionFactory.class.getClassLoader(),
        new Class[] { SqlSession.class },
        new SqlSessionInterceptor());

private class SqlSessionInterceptor implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      SqlSession sqlSession = getSqlSession(
          SqlSessionTemplate.this.sqlSessionFactory,
          SqlSessionTemplate.this.executorType,
          SqlSessionTemplate.this.exceptionTranslator);
      try {
        Object result = method.invoke(sqlSession, args);
        if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
          // force commit even on non-dirty sessions because some databases require
          // a commit/rollback before calling close()
          sqlSession.commit(true);
        }
        ......

五、DefaultSqlSession委托Executor执行

@Override
  public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
      MappedStatement ms = configuration.getMappedStatement(statement);
      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();
    }
  }

六、Executor执行查询

先从一级缓存查询,查询不到再从数据库查询

list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
      if (list != null) {
        handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
      } else {
        list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
      }

相关文章

网友评论

      本文标题:Mybatis查询流程

      本文链接:https://www.haomeiwen.com/subject/mgtogctx.html