mybatis源码阅读

发布时间 2023-08-10 19:25:39作者: 月习

配置解析

首先来看一个简单使用例子

String resource = "mybatis-config.xml";
//读取配置,创建sessionFactory
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(resource));
//opensession
SqlSession sqlSession = sessionFactory.openSession();
//获取mapper
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//执行接口方法
User user = mapper.findUserByNo("001");

下面会针对上面的步骤进行分析执行过程。读取配置会将配置文件中的配置读取到Configuration对象中进行存储。几个重要的属性

//存储已经解析的mapper文件类型,内部有map存储
MapperRegistry mapperRegistry;
//类型处理器注册表
TypeHandlerRegistry typeHandlerRegistry;
//类型昵称注册表
TypeAliasRegistry typeAliasRegistry;
//存储配置的增删改查操作语句
Map<String, MappedStatement> mappedStatements;
//resultMap映射集
Map<String, ResultMap> resultMaps;
//缓存集
Map<String, Cache> caches;
...
//还有很多公共的setting配置信息

XMLConfigBuilder.parse()会解析配置文件,将配置信息存储到Configuration对象中。

sessionFactory在opensession的时候会将解析的configuration信息传递给session。然后session.getMapper会从mapperRegistry中检查mapper是否已注册,如果已注册返回mapper接口类型的代理类,否则抛出异常。

动态代理

所有的mapper都是接口,这个时候调用mapper接口方法时候就是用的动态代理构建实例对象。

通过session获取mapper实例就是构造代理的过程。session的getMapper方法会调用Configuration的getMapper然后是MapperRegistry的。

MapperRegistry.getMapper方法源码

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
  final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
  if (mapperProxyFactory == null) {
    throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
  }
  try {//通过MapperProxyFactory获取代理实例对象
    return mapperProxyFactory.newInstance(sqlSession);
  } catch (Exception e) {
    throw new BindingException("Error getting mapper instance. Cause: " + e, e);
  }
}

MapperProxyFactory获取代理对象方法

public T newInstance(SqlSession sqlSession) {
  final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
  return newInstance(mapperProxy);
}
protected T newInstance(MapperProxy<T> mapperProxy) {
  //通过JDK的Proxy类构造代理对象
  return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}

MapperProxy类实现了InvocationHandler接口,其invoker方法执行会构造一个PlainMethodInvoker对象,最后会调用MapperMethod.execute()方法,来完成我们mapper接口的具体实现。来看看这个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方法会根据增删改查不同的指令进行相应的操作。

执行SQL

sql指令的发出都是通过DefaultSqlSession方法。

查询类:selectOne和selectList。selectOne会通过selectList来完成

修改:insert和update最后都会调用update

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

DefaultSqlSession.selectList()方法会调用Executor的query方法。session中的executor实例是CachingExecutor。

CachingExecutor.query(),

CachingExecutor会有一个SimpleExecutor类型的Executor来真正执行查询,SimpleExecutor继承自BaseExecutor,BaseExecutor实现了Executor。

方法源码:

BaseExecutor.queryFromDatabase()

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 {//doQuery调用的SimpleExecutor类方法
    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.doQuery

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();
    //这里创建的handler是RoutingStatementHandler
    StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
    stmt = prepareStatement(handler, ms.getStatementLog());
    return handler.query(stmt, resultHandler);
  } finally {
    closeStatement(stmt);
  }
}

RoutingStatementHandler.query

public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
  //这里的delegate是PreparedStatementHandler
  return delegate.query(statement, resultHandler);
}

PreparedStatementHandler.query

public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
  PreparedStatement ps = (PreparedStatement) statement;
  ps.execute();//执行查询
  //返回值处理
  return resultSetHandler.handleResultSets(ps);
}

最后还是通过PreparedStatement执行的sql操作。

返回值处理

  • 调用流程

以查询为例,DefaultResultSetHandler用来处理返回值。前面sql执行完后会调用DefaultResultSetHandler的handleResultSets(Statement stmt),实际处理方法在handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List