查看: 139|回复: 0

mybatis - 执行 getById

[复制链接]
发表于 2020-2-19 17:37:27 | 显示全部楼层 |阅读模式
1. getById 的实行

前面一篇 提到过, Mapper.java 创建的时候, 会通过 jdk 代理的方式来创建, 且代理处理类为: Mapperproxy .
以是当实行 UserMapper 的 getById 方法的时候, 就会去 MapperProxy 中实行 invoke 方法.
  1.   //MapperProxy.java   @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 =[b] cachedMapperMethod[/b](method);    return mapperMethod.[b]execute[/b](sqlSession, args);  }
复制代码
  1. cachedMapperMethod 方法是做了一层缓存处理. 先从缓存中获取, 假如获取不到, 再创建 MapperMethod 对象.
复制代码
  1.   private MapperMethod cachedMapperMethod(Method method) {    MapperMethod mapperMethod = methodCache.get(method);    if (mapperMethod == null) {      mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());      methodCache.put(method, mapperMethod);    }    return mapperMethod;  }
复制代码

接下来看一下 MapperMethod.execute() 方法. 这个方法中, 会看到我们期待的东西.
  1.   public Object execute(SqlSession sqlSession, Object[] args) {    Object result;    switch (command.getType()) {      case[b] INSERT[/b]: {      Object param = method.convertArgsToSqlCommandParam(args);        result = rowCountResult(sqlSession.insert(command.getName(), param));        break;      }      case[b] UPDATE[/b]: {        Object param = method.convertArgsToSqlCommandParam(args);        result = rowCountResult(sqlSession.update(command.getName(), param));        break;      }      case[b] DELETE[/b]: {        Object param = method.convertArgsToSqlCommandParam(args);        result = rowCountResult(sqlSession.delete(command.getName(), param));        break;      }      case[b] SELECT[/b]:        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 {
  2.       //对参数进行处理          Object param = method.convertArgsToSqlCommandParam(args);          result = sqlSession.[b]selectOne[/b](command.getName(), param);        }        break;      case[b] FLUSH[/b]:        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;  }
复制代码
getById 在这里会调用 SQLSessionTemplate 的 selectOne 方法.
  1.   //SqlSessionTemplate.java    @Override  public  T selectOne(String statement, Object parameter) {    return this.sqlSessionProxy. selectOne(statement, parameter);  }
复制代码
前面解析过, sqlSessionProxy.selectOne 的时候, 会去  SqlSessionInterceptor 中实行 invoke() 方法.
  1.   private class SqlSessionInterceptor implements InvocationHandler {    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {      SqlSession sqlSession =[b] getSqlSession[/b](          SqlSessionTemplate.this.sqlSessionFactory,          SqlSessionTemplate.this.executorType,          SqlSessionTemplate.this.exceptionTranslator);      try {        Object result = method.[b]invoke[/b](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);        }        return result;      } catch (Throwable t) {        Throwable unwrapped = unwrapThrowable(t);        if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {          // release the connection to avoid a deadlock if the translator is no loaded. See issue #22          closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);          sqlSession = null;          Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);          if (translated != null) {            unwrapped = translated;          }        }        throw unwrapped;      } finally {        if (sqlSession != null) {          closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);        }      }    }  }
复制代码
这里有两个方法需要重点关注, 一个是  getSqlSession() , 另一个是 invoke() 方法.
1.1 getSqlSession()
  1.   public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {    notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED);    notNull(executorType, NO_EXECUTOR_TYPE_SPECIFIED);    SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);    SqlSession session = sessionHolder(executorType, holder);    if (session != null) {      return session;    }    if (LOGGER.isDebugEnabled()) {      LOGGER.debug("Creating a new SqlSession");    }    session = sessionFactory.[b]openSession[/b](executorType);    registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);    return session;  }
复制代码
这里的 SqlSessionFactory 就是设置类中创建的 默认的实现类: DefaultSqlSessionFactory
  1.   //DefaultSqlSessionFactory.java  @Override  public SqlSession openSession(ExecutorType execType) {    return openSessionFromDataSource(execType, null, false);  } | |\|/  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);      final Executor executor = configuration.newExecutor(tx, execType);      return new[b] DefaultSqlSession[/b](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();    }  }
复制代码
这里先不管别的代码, 直接看返回值, 创建了一个 DefaultSqlSession 的实例返回.

1.2 method.invoke()

回到 SqlSessionInterceptor 中来, 继续看下面的实行代码:
  1. Object result = method.invoke(sqlSession, args);
复制代码
sqlSession 就是上面创建的 DefaultSqlSesion 实例. 我们知道 Method.invoke(obj, args) 是反射调用方法的一种方式.
此处的Method是 getById 的方法反射类型. 以是, 会调用 obj 的 getById() 方法, 即 DefaultSqlSession 的 getById() 方法.
  1.   @Override  public  T selectOne(String statement, Object parameter) {    // Popular vote was to return null on 0 results and throw exception on too many.    List list = this.[b]selectList[/b](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  List selectList(String statement, Object parameter) {    return this.selectList(statement, parameter, RowBounds.DEFAULT);  }  @Override  public  List selectList(String statement, Object parameter, RowBounds rowBounds) {    try {      [b]MappedStatement[/b] ms = configuration.[b]getMappedStatement[/b](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();    }  }
复制代码
此例中, statement = "com.study.demo.mybatis.mapper.UserMapper.getById"
这里是通过statement 拿 MappedStatement, 而 MappedStatement 中, 就有 mapper.xml 中对应的 sql 语句.
后续过程中, 就可以拿着 sql 去数据库实行了.
到这里, 主体流程实在已经走通了.

天涯海角也要找到Ni:mybatis - 执行 getById

中发现Ni: mybatis - 执行 getById
中发现Ni: mybatis - 执行 getById
中发现Ni: mybatis - 执行 getById
中发现Ni: mybatis - 执行 getById
中发现Ni: mybatis - 执行 getById
中发现Ni: mybatis - 执行 getById
相关技术服务需求,请联系管理员和客服QQ:2753533861或QQ:619920289
您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

帖子推荐:
客服咨询

QQ:2753533861

服务时间 9:00-22:00

快速回复 返回顶部 返回列表