Mybatis中mapper接口实现和方法的执行

mybatis实现mapper接口的原理,并且绑定对应xml

1.mybatis加载mapper接口和xml的几种方式

​ 1.在mybait配置文件中进行配置文件中进行配置,在mappers标签下配置mapper.xml的文件加载路径,一般都会配置在resource包下

<mappers>
    <mapper resource="mapper/xxxMapper.xml"/>
</mappers>

​ 对应的mapper.xml文件都有mapper接口的路径,maybatis通过该路径加载对应的mapper接口

<mapper namespace="org.apache.ibatis.test.mapper.UserMapper">

​ 2.同样在mybait配置文件中进行配置文件中进行配置,在mapper标签下配置对应mapper接口所在包路径,同时对应的xml文件也需要配置在改包下,mybaits通过当前接口找到对应的xml文件

注意,提供maven进行编译的时候不会把在java包下的xml文件加载到classes下,所以需要配置对应加载resources标签)

  <mappers>
      <package name="org.apache.ibatis.test.mapper"/>
    </mappers>

3.通过与spring整合,通过@MapperScan注解扫描对应的mapper进行实现,xml文件需要和机器对应的接口写在同一包下,名称也需要相同

// Springboot启动方式
@SpringBootApplication
@MapperScan({“com.kfit.demo”,“com.kfit.user”})
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}

4.整和MybatisPlus,通过配置yml属性的方式进行加载

mybatis-plus:
      mapper-locations: # mapper.xml文件路径,例如:classpath:*/mapper/**/*

综上可以得出,mybait配置maperr接口和xml方式可以选择直接配置xml或mapper接口路径来实现,mapper接口方式需要把xml和mapper接口卸载一起

2.mapper接口和xml文件进行绑定流程

1.先解析xml文件,在绑定mapper接口源码流程

​ 1.解析mybaitis-config.xml文件,解析mappers节点(直接配置mybaitis-config.xml文件的时候会进行解析加载)

private void parseConfiguration(XNode root) {
  try {
    // issue #117 read properties first
    propertiesElement(root.evalNode("properties"));
    Properties settings = settingsAsProperties(root.evalNode("settings"));
    loadCustomVfs(settings);
    loadCustomLogImpl(settings);
    typeAliasesElement(root.evalNode("typeAliases"));
    pluginElement(root.evalNode("plugins"));
    objectFactoryElement(root.evalNode("objectFactory"));
    objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
    reflectorFactoryElement(root.evalNode("reflectorFactory"));
    settingsElement(settings);
    // read it after objectFactory and objectWrapperFactory issue #631
    environmentsElement(root.evalNode("environments"));
    databaseIdProviderElement(root.evalNode("databaseIdProvider"));
    typeHandlerElement(root.evalNode("typeHandlers"));
    mapperElement(root.evalNode("mappers")); // 解析mybatis-config.xml下的mappers标签
  } catch (Exception e) {
    throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
  }
}

2.根据mappers标签下的子标签判断是加载xxxMapper.xml文件还是加载mapper接口所在包

private void mapperElement(XNode parent) throws Exception {
  if (parent != null) {
      // 遍历子节点
    for (XNode child : parent.getChildren()) {
        // 如果是package标签,则则获取name属性,name属性相当于我们配置的mapper接口的包路径,mybaits会加载所有接口和其对应的xml文件放到Configuration属性中去
      if ("package".equals(child.getName())) {
        String mapperPackage = child.getStringAttribute("name");
          // Configuration加载mapper接口
        configuration.addMappers(mapperPackage);
      } else {
          // 解析xml加载方式
        String resource = child.getStringAttribute("resource");
        String url = child.getStringAttribute("url");
          // 直接加载mapper接口方式
        String mapperClass = child.getStringAttribute("class");
        if (resource != null && url == null && mapperClass == null) {
          ErrorContext.instance().resource(resource);
          try(InputStream inputStream = Resources.getResourceAsStream(resource)) {
  			// 通过配置resource路径加载,创建mapperXMl解析器
            XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
              // 解析xml
            mapperParser.parse();
          }
        } else if (resource == null && url != null && mapperClass == null) {
            // 通过url方式加载xml
          ErrorContext.instance().resource(url);
          try(InputStream inputStream = Resources.getUrlAsStream(url)){
            XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
            mapperParser.parse();
          }
        } else if (resource == null && url == null && mapperClass != null) {
            // 加载mapper接口,通过mapper接口找到其对应xml
          Class<?> mapperInterface = Resources.classForName(mapperClass);
          configuration.addMapper(mapperInterface);
        } else {
          throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
        }
      }
    }
  }
}

3.解析xxxmapper.xml文件

private void configurationElement(XNode context) {
  try {
    // 对应的mapper接口路径
    String namespace = context.getStringAttribute("namespace");
    if (namespace == null || namespace.isEmpty()) {
      throw new BuilderException("Mapper's namespace cannot be empty");
    }
    builderAssistant.setCurrentNamespace(namespace);
    // 解析缓存相关属性,默认创建本地缓存,缓存机制为lru
    cacheRefElement(context.evalNode("cache-ref"));
    cacheElement(context.evalNode("cache"));
      // 过时
    parameterMapElement(context.evalNodes("/mapper/parameterMap"));
      // 解析resultmap
    resultMapElements(context.evalNodes("/mapper/resultMap"));
      // 解析sql片段
    sqlElement(context.evalNodes("/mapper/sql"));
      // 解析ddl语句,创建MappedStatement放入configurdation中
    buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
  } catch (Exception e) {
    throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e);
  }
}
public void parse() {
  if (!configuration.isResourceLoaded(resource)) {
     // 解析mapper.xml
    configurationElement(parser.evalNode("/mapper"));
    configuration.addLoadedResource(resource);
     // 加载mapper接口到configuration
    bindMapperForNamespace();
  }
	// 解析一下待处理的数据集合
  parsePendingResultMaps();
  parsePendingCacheRefs();
  parsePendingStatements();
}
private void bindMapperForNamespace() {
    // 解析mapper接口所在路径
  String namespace = builderAssistant.getCurrentNamespace();
  if (namespace != null) {
    Class<?> boundType = null;
    try {
      boundType = Resources.classForName(namespace);
    } catch (ClassNotFoundException e) {
      // ignore, bound type is not required
    }
      // configurayion不存在当前mapper接口,把mapper放到configuration中去
    if (boundType != null && !configuration.hasMapper(boundType)) {
      // Spring may not know the real resource name so we set a flag
      // to prevent loading again this resource from the mapper interface
      // look at MapperAnnotationBuilder#loadXmlResource
      configuration.addLoadedResource("namespace:" + namespace);
      configuration.addMapper(boundType);
    }
  }
}
public <T> void addMapper(Class<T> type) {
  if (type.isInterface()) {
    if (hasMapper(type)) {
      throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
    }
    boolean loadCompleted = false;
     
    try {
        // 创建mapper接口代理工厂
      knownMappers.put(type, new MapperProxyFactory<>(type));
      // It's important that the type is added before the parser is run
      // otherwise the binding may automatically be attempted by the
      // mapper parser. If the type is already known, it won't try.
        // 解析mapper接口注解,加载xml文件(解析mapper接口上的注解信息)
      MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
      // 解析记载的mapper接口,
      parser.parse();
      loadCompleted = true;
    } finally {
      if (!loadCompleted) {
        knownMappers.remove(type);
      }
    }
  }
}
public void parse() {
    // 加载xml文件
  String resource = type.toString();
  if (!configuration.isResourceLoaded(resource)) {
    loadXmlResource();
    configuration.addLoadedResource(resource);
    assistant.setCurrentNamespace(type.getName());
    parseCache();
    parseCacheRef();
    for (Method method : type.getMethods()) {
      if (!canHaveStatement(method)) {
        continue;
      }
        // 解析注解属性
      if (getAnnotationWrapper(method, false, Select.class, SelectProvider.class).isPresent()
          && method.getAnnotation(ResultMap.class) == null) {
        parseResultMap(method);
      }
      try {
        parseStatement(method);
      } catch (IncompleteElementException e) {
        configuration.addIncompleteMethod(new MethodResolver(this, method));
      }
    }
  }
   // 解析mapper接口中的方法放入configuration
  parsePendingMethods();
}

2.先加载mapper接口,在绑定xml文件流程

1.加载mapper接口所在包路径,获取所有的mapper接口

configuration.addMappers(mapperPackage);
public void addMappers(String packageName, Class<?> superType) {
  // 解析包路径
  ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<>();
  resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
   // 拿到所有当前包路径下的mapper接口
  Set<Class<? extends Class<?>>> mapperSet = resolverUtil.getClasses();
  for (Class<?> mapperClass : mapperSet) {
      // 加载解析mapper接口
    addMapper(mapperClass);
  }
}
//  加载mapper接口,同时在加载xml文件
public <T> void addMapper(Class<T> type) {
  if (type.isInterface()) {
    if (hasMapper(type)) {
      throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
    }
    boolean loadCompleted = false;
    try {
      knownMappers.put(type, new MapperProxyFactory<>(type));
      // It's important that the type is added before the parser is run
      // otherwise the binding may automatically be attempted by the
      // mapper parser. If the type is already known, it won't try.
      MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
      parser.parse();
      loadCompleted = true;
    } finally {
      if (!loadCompleted) {
        knownMappers.remove(type);
      }
    }
  }
}

流程总结

1.mapper接口会保存在configuration中的mapperRegistry对象中,MapperRegistry有一个MapperProxyFactory的缓存表,mapper接口以MapperProxyFactory代理类的形势进行存储。

public class MapperRegistry {

  private final Configuration config;
  private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<>();

2.mapper接口中的方法和xml的方法解析以后会存储在configuration的mappedStatements中

protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection")
    .conflictMessageProducer((savedValue, targetValue) ->
        ". please check " + savedValue.getResource() + " and " + targetValue.getResource());

xml中的方法不能重复

3.一个简单sql的执行

1.获取mapper接口代理

​ 开启一个会话(mybatis的一般步骤,通常会由spring进行管理)

SqlSession session = sqlSessionFactory.openSession();  // 开启会话
XxxMapper mapper = session.getMapper(XxxMapper.class); // 获取mapper接口
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 DefaultSqlSession(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();
  }
}

2.获取方法增强代理

UserMapper mapper = session.getMapper(UserMapper.class); // 通过接口获取代理对象
// 在MapperRegistry中获取对应的代理类
MapperProxyFactory

@SuppressWarnings("unchecked")
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
  final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type); // 从knownmappers中获取,相当于代理类工厂缓存对象
  if (mapperProxyFactory == null) {
    throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
  }
  try {
      // 通过代理工厂生成接口实现类 jdk动态代理
    T t = mapperProxyFactory.newInstance(sqlSession);
    return t;
  } catch (Exception e) {
    throw new BindingException("Error getting mapper instance. Cause: " + e, e);
  }
}
// 代理类生成工厂,
public class MapperProxyFactory<T> {
// 接口对象
  private final Class<T> mapperInterface;
    // 代理方法实现缓存 mapper接口实现类的方法实现
  private final Map<Method, MapperMethodInvoker> methodCache = new ConcurrentHashMap<>();

  public MapperProxyFactory(Class<T> mapperInterface) {
    this.mapperInterface = mapperInterface;
  }

  public Class<T> getMapperInterface() {
    return mapperInterface;
  }

  public Map<Method, MapperMethodInvoker> getMethodCache() {
    return methodCache;
  }

  @SuppressWarnings("unchecked")
  protected T newInstance(MapperProxy<T> mapperProxy) {
     // jdk动态代理生成实现类,增强方法为mapperProxy的invoke
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }
	// 生成代理类,传入MapperProxy,MapperProxy实现了InvocationHandler,相当于接口方法增强实现类
  public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }

}

3.执行sql

调用mapper接口的方法

首先执行InvocationHandler的实现类MapperProxy的invoke方法

@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 {
          // 创建mappermethod类
        return new PlainMethodInvoker(new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
      }
    });
  } catch (RuntimeException re) {
    Throwable cause = re.getCause();
    throw cause == null ? re : cause;
  }
}

创建MapperMethod类,创建SqlCommand类

public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
  this.command = new SqlCommand(config, mapperInterface, method);
    // 方法签名,返回类型,请求参数解析
  this.method = new MethodSignature(config, mapperInterface, method);
}
public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {
  final String methodName = method.getName();
  final Class<?> declaringClass = method.getDeclaringClass();
    // 获取MappedStatement(从Map<String, MappedStatement> mappedStatements 缓存中获取)
  MappedStatement ms = resolveMappedStatement(mapperInterface, methodName, declaringClass,
      configuration);
  if (ms == null) {
    if (method.getAnnotation(Flush.class) != null) {
      name = null;
      type = SqlCommandType.FLUSH;
    } else {
      throw new BindingException("Invalid bound statement (not found): "
          + mapperInterface.getName() + "." + methodName);
    }
  } else {
     //包装属性
    name = ms.getId();
    type = ms.getSqlCommandType();
    if (type == SqlCommandType.UNKNOWN) {
      throw new BindingException("Unknown execution method for: " + name);
    }
  }
}
public MethodSignature(Configuration configuration, Class<?> mapperInterface, Method method) {
  Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface);
    // 判断返回类型
  if (resolvedReturnType instanceof Class<?>) {
    this.returnType = (Class<?>) resolvedReturnType;
  } else if (resolvedReturnType instanceof ParameterizedType) {
    this.returnType = (Class<?>) ((ParameterizedType) resolvedReturnType).getRawType();
  } else {
    this.returnType = method.getReturnType();
  }
  this.returnsVoid = void.class.equals(this.returnType);
  this.returnsMany = configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray();
  this.returnsCursor = Cursor.class.equals(this.returnType);
  this.returnsOptional = Optional.class.equals(this.returnType);
  this.mapKey = getMapKey(method);
  this.returnsMap = this.mapKey != null;
  this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);
  this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);
  this.paramNameResolver = new ParamNameResolver(configuration, method);
}

方法执行

MapperMethod的invoke方法
@Override
public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {
  return mapperMethod.execute(sqlSession, args);
}

根据不同的方法类型进行调用

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;
}

数据查询

@Override
public <T> T selectOne(String statement, Object parameter) {
  // Popular vote was to return null on 0 results and throw exception on too many.
  List<T> list = this.selectList(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;
  }
}
     
     private <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
    try {
        // 获取 MappedStatement
      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();
    }
  } 
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    // 包装sql
  BoundSql boundSql = ms.getBoundSql(parameterObject);
    // 获取缓存key
  CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
    // 执行查询
  return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
@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);
    stmt = prepareStatement(handler, ms.getStatementLog());
    
    return handler.query(stmt, resultHandler);
  } finally {
    closeStatement(stmt);
  }
}
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
   // JDBC执行查询
  PreparedStatement ps = (PreparedStatement) statement;
  ps.execute();
   // 封装返回结果
  return resultSetHandler.handleResultSets(ps);
}

4.包装返回结果

// 处理resultset jdbc原生返回结果集合
public List<Object> handleResultSets(Statement stmt) throws SQLException {
  ErrorContext.instance().activity("handling results").object(mappedStatement.getId());

   // 返回结果集合
  final List<Object> multipleResults = new ArrayList<>();

  int resultSetCount = 0;
    // 结果包装器
  ResultSetWrapper rsw = getFirstResultSet(stmt);

   // 获取resultmap结果集映射,没有指定会根据返回类自动创建一个
  List<ResultMap> resultMaps = mappedStatement.getResultMaps();
  int resultMapCount = resultMaps.size();
   // 校验是否存在resultmap
  validateResultMapsCount(rsw, resultMapCount);
    // 根据resultmap的数量遍历结果
  while (rsw != null && resultMapCount > resultSetCount) {
    ResultMap resultMap = resultMaps.get(resultSetCount);
    // 处理返回结果集合
    handleResultSet(rsw, resultMap, multipleResults, null);
    rsw = getNextResultSet(stmt);
      // 清空内置结果集和映射
    cleanUpAfterHandlingResultSet();
     // resultset对应resyktmap处理次数加一
    resultSetCount++;
  }

   // 处理内置结果集合映射
  String[] resultSets = mappedStatement.getResultSets();
  if (resultSets != null) {
    while (rsw != null && resultSetCount < resultSets.length) {
      ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
      if (parentMapping != null) {
        String nestedResultMapId = parentMapping.getNestedResultMapId();
        ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
      
        handleResultSet(rsw, resultMap, null, parentMapping);
      }
      rsw = getNextResultSet(stmt);
      
      cleanUpAfterHandlingResultSet();
      resultSetCount++;
    }
  }

  return collapseSingleResultList(multipleResults);
}
// 创建resultset包装器
private ResultSetWrapper getFirstResultSet(Statement stmt) throws SQLException {
  ResultSet rs = stmt.getResultSet();
  while (rs == null) {
    // move forward to get the first resultset in case the driver
    // doesn't return the resultset as the first result (HSQLDB 2.1)
    if (stmt.getMoreResults()) {
      rs = stmt.getResultSet();
    } else {
      if (stmt.getUpdateCount() == -1) {
        // no more results. Must be no resultset
        break;
      }
    }
  }
  return rs != null ? new ResultSetWrapper(rs, configuration) : null;
}
public ResultSetWrapper(ResultSet rs, Configuration configuration) throws SQLException {
  super();
   // 类型处理器
  this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
  this.resultSet = rs;
   // 原数据集合
  final ResultSetMetaData metaData = rs.getMetaData();
  final int columnCount = metaData.getColumnCount();
  for (int i = 1; i <= columnCount; i++) {
      // 数据库字段名称集合
    columnNames.add(configuration.isUseColumnLabel() ? metaData.getColumnLabel(i) : metaData.getColumnName(i));
      // jdbc类型集合
    jdbcTypes.add(JdbcType.forCode(metaData.getColumnType(i)));
     // 数据库字段对应的java类型类名称集合
    classNames.add(metaData.getColumnClassName(i));
  }
}
private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
  try {
    if (parentMapping != null) {
      handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
    } else {
      if (resultHandler == null) {
        // 创建默认结果处理器,内部创建一个list空集合
        DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
        // 处理结果集每一行数据
        handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
        // 把返回结果放入multipleResults
        multipleResults.add(defaultResultHandler.getResultList());
      } else {
        handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
      }
    }
  } finally {
    // issue #228 (close resultsets)
     // 关闭ResultSet,数据处理完毕
    closeResultSet(rsw.getResultSet());
  }
}
// 处理简单结果集映射对象的返回结果
private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
    throws SQLException {
    // 结果集合context,用来传递数据
  DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
  ResultSet resultSet = rsw.getResultSet();
   // 跳过不需要的行数据
  skipRows(resultSet, rowBounds);
  while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
    ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
    // 获取每一行的数据
    Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
     // 存储当前行数据
    storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
  }
}
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
  final ResultLoaderMap lazyLoader = new ResultLoaderMap();
  // 创建结果集对象
  Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
  if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
      // 创建结果对象的元数据包装对象
    final MetaObject metaObject = configuration.newMetaObject(rowValue);
    boolean foundValues = this.useConstructorMappings;
    if (shouldApplyAutomaticMappings(resultMap, false)) {
       // 单行对象数据,字段名词,数据类型,自动映射(数据不存在别名映射),从jdbc结果集合中根据字段类型和名词把数据填充到对象的对象属性中去
      foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
    }
      //  不存在别名映射的属性填充
    foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
    foundValues = lazyLoader.size() > 0 || foundValues;
    rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
  }
  return rowValue;
}

4.与spring的整合使用

1.添加对应的maven依赖

2.在配置类上添加@MapperScan注解。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值