Mybatis的署理对象MapperProxy的CURD

藏宝库编辑 2024-9-7 21:35:20 38 0 来自 中国
上篇-原生mybatis流程
因Mapper是interface,不能实例化对象,以是必须使用动态署理(使用JDK动态署理)创建署理对象MapperProxy,又因Mapper是接口,没有具体的方法体,以是MapperProxy的invoke方法中自行编写方法逻辑,下面先容CURD的实行过程。
public class MapperProxy<T> implements InvocationHandler, Serializable {略@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 {        return cachedInvoker(method).invoke(proxy, method, args, sqlSession);      }    } catch (Throwable t) {      throw ExceptionUtil.unwrapThrowable(t);    }  }  private MapperMethodInvoker cachedInvoker(Method method) throws Throwable {    try {      return MapUtil.computeIfAbsent(methodCache, method, m -> {        if (m.isDefault()) {          try {            if (privateLookupInMethod == null) {              return new DefaultMethodInvoker(getMethodHandleJava8(method));            } else {              return new DefaultMethodInvoker(getMethodHandleJava9(method));            }          } catch (IllegalAccessException | InstantiationException | InvocationTargetException              | NoSuchMethodException e) {            throw new RuntimeException(e);          }        } else {          return new PlainMethodInvoker(new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));        }      });    } catch (RuntimeException re) {      Throwable cause = re.getCause();      throw cause == null ? re : cause;    }  }}###调用MapperBean中的非default方法  private static class PlainMethodInvoker implements MapperMethodInvoker {    private final MapperMethod mapperMethod;    public PlainMethodInvoker(MapperMethod mapperMethod) {      super();      this.mapperMethod = mapperMethod;    }    @Override    public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {      return mapperMethod.execute(sqlSession, args);    }  }可见mapperMethod来实行execute,携带sqlSession和参数(默认的statement是prepareStatement)

mapperMethod类中有2个属性,分别是SqlCommand、MethodSignature,均是MapperMethod的内部类。
public class MapperMethod {  private final SqlCommand command;  private final MethodSignature method;  public static class SqlCommand {    类全路径名+方法名:com.orion.mapper.TAccountMapper.selectByPrimaryKey    private final String name;    罗列,CURD那几种,如SELECT    private final SqlCommandType type;  }    public static class MethodSignature {    private final boolean returnsMany;    private final boolean returnsMap;    private final boolean returnsVoid;    private final boolean returnsCursor;    private final boolean returnsOptional;    返回范例    private final Class<?> returnType;    private final String mapKey;    private final Integer resultHandlerIndex;    private final Integer rowBoundsIndex;    参数    private final ParamNameResolver paramNameResolver;  }  }SELECT

debug下去终极实行execute之类的方法,而实行的execute方法是sqlSession,注意sqlSession是携带configuration的,configuration内里有mappedStatement(全部方法聚集),末了根据SqlCommand中的name作为id从mappedStatement中获取相应的MappedStatement对象。
DefaultSqlSession:  private <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {    try {      MappedStatement ms = configuration.getMappedStatement(statement);      return executor.query(ms, wrapCollection(parameter), rowBounds, handler);    } catch (Exception e) {      throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);    } finally {      ErrorContext.instance().reset();    }  }CachingExecutor:  @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);  }MappedStatement:  public BoundSql getBoundSql(Object parameterObject) {    BoundSql boundSql = sqlSource.getBoundSql(parameterObject);    List<arameterMapping> parameterMappings = boundSql.getParameterMappings();    if (parameterMappings == null || parameterMappings.isEmpty()) {      boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);    }    // check for nested result maps in parameter mappings (issue #30)    for (ParameterMapping pm : boundSql.getParameterMappings()) {      String rmId = pm.getResultMapId();      if (rmId != null) {        ResultMap rm = configuration.getResultMap(rmId);        if (rm != null) {          hasNestedResultMaps |= rm.hasNestedResultMaps();        }      }    }    return boundSql;  }  public BoundSql getBoundSql(Object parameterObject) {    BoundSql boundSql = sqlSource.getBoundSql(parameterObject);    List<arameterMapping> parameterMappings = boundSql.getParameterMappings();    if (parameterMappings == null || parameterMappings.isEmpty()) {      boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);    }boundSql内下属性,具有sql以及参数mapping

3.png 终极去到BaseExecutor,实行query方法,第一次没有缓存,走queryFromDatabase方法,注意一级缓存是session级别,二级缓存才是最大范围全局的。

  @SuppressWarnings("unchecked")  @Override  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 (closed) {      throw new ExecutorException("Executor was closed.");    }    if (queryStack == 0 && ms.isFlushCacheRequired()) {      clearLocalCache();    }    List<E> list;    try {      queryStack++;      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);      }    } finally {      queryStack--;    }    if (queryStack == 0) {      for (DeferredLoad deferredLoad : deferredLoads) {        deferredLoad.load();      }      // issue #601      deferredLoads.clear();      if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {        // issue #482        clearLocalCache();      }    }    return list;  }查询数据库,将Cachekey加入本地内存  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;  }SimpleExecutor:  @Override  public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {    Statement stmt = null;    try {      Configuration configuration = ms.getConfiguration();      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);       !!!参数mapping,stmt是一个proxy      stmt = prepareStatement(handler, ms.getStatementLog());      return handler.query(stmt, resultHandler);    } finally {      closeStatement(stmt);    }  }  private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {    Statement stmt;    Connection connection = getConnection(statementLog);    stmt = handler.prepare(connection, transaction.getTimeout());    //参数按照index嵌入,无参数的也是prepareStatementHandler ,只是parameterize里不会循环而已    handler.parameterize(stmt);    return stmt;  }ConnectionLogger:@Override  public Object invoke(Object proxy, Method method, Object[] params)      throws Throwable {    try {      if (Object.class.equals(method.getDeclaringClass())) {        return method.invoke(this, params);      }      if ("prepareStatement".equals(method.getName()) || "prepareCall".equals(method.getName())) {        if (isDebugEnabled()) {          debug(" Preparing: " + removeExtraWhitespace((String) params[0]), true);        }        PreparedStatement stmt = (PreparedStatement) method.invoke(connection, params);        stmt = PreparedStatementLogger.newInstance(stmt, statementLog, queryStack);        return stmt;      } else if ("createStatement".equals(method.getName())) {        Statement stmt = (Statement) method.invoke(connection, params);        stmt = StatementLogger.newInstance(stmt, statementLog, queryStack);        return stmt;      } else {        return method.invoke(connection, params);      }    } catch (Throwable t) {      throw ExceptionUtil.unwrapThrowable(t);    }  }末了结果resultMap匹配映射,返回结果集,完成过程

PreparedStatementHandler:  @Override  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {    PreparedStatement ps = (PreparedStatement) statement;    ps.execute();    return resultSetHandler.handleResultSets(ps);  } 5.png 剩下的增加、删除、修改

MapperMethod:rowCountResult就是返回影响行数  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;  }它们末了都是实行DefaultSqlSession中的update方法:
DefaultSqlSession:  @Override  public int update(String statement, Object parameter) {    try {      dirty = true;      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();    }  }SimpleExecutor  @Override  public int update(MappedStatement ms, Object parameter) throws SQLException {    ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());    if (closed) {      throw new ExecutorException("Executor was closed.");    }    update就是要清除LocalCache    clearLocalCache();    return doUpdate(ms, parameter);  }  @Override  public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {主体代码和select差不多    Statement stmt = null;    try {      Configuration configuration = ms.getConfiguration();      StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);      stmt = prepareStatement(handler, ms.getStatementLog());      return handler.update(stmt);    } finally {      closeStatement(stmt);    }  } PreparedStatementHandler :  @Override  public int update(Statement statement) throws SQLException {    PreparedStatement ps = (PreparedStatement) statement;    ps.execute();    int rows = ps.getUpdateCount();    Object parameterObject = boundSql.getParameterObject();    KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();    keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);    return rows;  }终极得到影响行数,竣事。
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-10-19 04:21, Processed in 0.166069 second(s), 35 queries.© 2003-2025 cbk Team.

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