Mybatis源码分析 v1.0

第一节 参考


一.参考资料
https://github.com/mybatis/mybatis-3

mybatis的单元测试用的hsqldb数据库,需要自己建个单元测试用例, 连接mysql.我的测试用例如下图所示.

第二节 架构


一.分层
核心原理三步走:
1.启动读取xml配置,解析到Configuration类中,以Configuration为构造方法参数创建SqlSessionFactory
2.通过DefaultSqlSessionFactory类创建DefaultSqlSession,通过DefaultSqlSession获取到mapper接口的代理类.
3.通过mapper接口的代理类执行sql语句


具体过程:
Configuration+代理+命令模式+委托模式。
所有的mybatis配置读取xml到Configuration类中. 然后调用MapperProxyFactory类,生成所有mapper接口类的代理类MapperProxy.在MapperProxy类的invoke方法中,调用MapperMethod.execute方法中执行各种命令.具体命令由RoutingStatementHandler委托具体的类处理,执行由STATEMENT,PREPARED,CALLABLE类型的具体类型处理.


二.SqlSessionFactoryBuilder/SqlSessionFactory
三.SqlSession
四.Configuration
五.Executor
六.BoundSql
七.StatementHandler
八.ResultSetHandler

 

第三节 源码细节

 

一.启动读取xml配置,创建SqlSessionFactory
调用SqlSessionFactoryBuilder#build(Reader)使用builder模式创建创建SqlSessionFactory.入参是是xml文件生成的Reader.主要是填充Configuration类对象,然后把这个对象作为DefaultSqlSessionFactory构造方法的参数.
xml文件使用sax库解析到XMLConfigBuilder类中.然后进入XMLConfigBuilder#parseConfiguration(XNode)解析到Configuration类型的BaseBuilder#configuration成员中.XMLConfigBuilder类继承自BaseBuilder类,BaseBuilder类中成员如下:

public abstract class BaseBuilder {
  //xml中的各种配置
  protected final Configuration configuration;
  protected final TypeAliasRegistry typeAliasRegistry;
  protected final TypeHandlerRegistry typeHandlerRegistry;
}

1.解析xml内容的方法XMLConfigBuilder#parseConfiguration()代码如下:

private void parseConfiguration(XNode root) {
    try {
      //issue #117 read properties first
      /* 解析properties标签中的name value值存储到Properties类型的Configuration#variables成员中
      比如示例代码中的<property name="dialect" value="mysql" /> */
      propertiesElement(root.evalNode("properties"));
      /* 解析setting标签为Properties格式,比如示例中的<setting name="mapUnderscoreToCamelCase" value="true" /> */
      Properties settings = settingsAsProperties(root.evalNode("settings"));
      //解析VFS的子类放到Configuration#vfsImpl成员中,没用过
      loadCustomVfs(settings);
      //解析Log接口的实现类放到Configuration#logImpl成员中,没用过
      loadCustomLogImpl(settings);
      /* 解析typeAliases,调用TypeAliasRegistry#registerAliases()注册类型别名到TypeAliasRegistry#TYPE_ALIASES成员Map中*/
      typeAliasesElement(root.evalNode("typeAliases"));
      /*注册plugins插件到类型为InterceptorChain的Configuration#interceptorChain中*/
      pluginElement(root.evalNode("plugins"));
      /*解析objectFactory到类型为ObjectFactory的Configuration#objectFactory成员中*/
      objectFactoryElement(root.evalNode("objectFactory"));
      /*解析objectWrapperFactory到类型为ObjectWrapperFactory的成员Configuration#objectWrapperFactory中*/
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      /*解析reflectorFactory标签到类型为ReflectorFactory的成员Configuration#reflectorFactory中*/
      reflectorFactoryElement(root.evalNode("reflectorFactory"));
      /*解析setting标签到configuration成员中,具体支持的设置项入下面代码2处所示.*/
      settingsElement(settings);
      // read it after objectFactory and objectWrapperFactory issue #631
      /*解析environments标签到类型为Environment的成员Configuration#environment中这里面存放了jdbc连接的配置,Environment类成员在下面代码给出*/
      environmentsElement(root.evalNode("environments"));
      /*解析databaseIdProvider标签的值到Configuration#databaseId*/
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      /*解析typeHandlers到TypeHandlerRegistry#TYPE_HANDLER_MAP的成员map中*/
      typeHandlerElement(root.evalNode("typeHandlers"));
      /*注册所有xml的mapper文件,内部逻辑是针对每个xml文件,创建XMLMapperBuilder对象,调用XMLMapperBuilder#parse()解析mapper文件,代码在后面3处分析*/
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
}

Environment类成员:

public final class Environment {
  private final String id;
  private final TransactionFactory transactionFactory;
  private final DataSource dataSource;
}

2.mybatis支持的setting配置项
进入XMLConfigBuilder#settingsElement()方法,代码如下:

private void settingsElement(Properties props) {
    configuration.setAutoMappingBehavior(AutoMappingBehavior.valueOf(props.getProperty("autoMappingBehavior", "PARTIAL")));
    configuration.setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior.valueOf(props.getProperty("autoMappingUnknownColumnBehavior", "NONE")));
    configuration.setCacheEnabled(booleanValueOf(props.getProperty("cacheEnabled"), true));
    configuration.setProxyFactory((ProxyFactory) createInstance(props.getProperty("proxyFactory")));
    configuration.setLazyLoadingEnabled(booleanValueOf(props.getProperty("lazyLoadingEnabled"), false));
    configuration.setAggressiveLazyLoading(booleanValueOf(props.getProperty("aggressiveLazyLoading"), false));
    configuration.setMultipleResultSetsEnabled(booleanValueOf(props.getProperty("multipleResultSetsEnabled"), true));
    configuration.setUseColumnLabel(booleanValueOf(props.getProperty("useColumnLabel"), true));
    configuration.setUseGeneratedKeys(booleanValueOf(props.getProperty("useGeneratedKeys"), false));
    configuration.setDefaultExecutorType(ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE")));
    configuration.setDefaultStatementTimeout(integerValueOf(props.getProperty("defaultStatementTimeout"), null));
    configuration.setDefaultFetchSize(integerValueOf(props.getProperty("defaultFetchSize"), null));
    configuration.setMapUnderscoreToCamelCase(booleanValueOf(props.getProperty("mapUnderscoreToCamelCase"), false));
    configuration.setSafeRowBoundsEnabled(booleanValueOf(props.getProperty("safeRowBoundsEnabled"), false));
    configuration.setLocalCacheScope(LocalCacheScope.valueOf(props.getProperty("localCacheScope", "SESSION")));
    configuration.setJdbcTypeForNull(JdbcType.valueOf(props.getProperty("jdbcTypeForNull", "OTHER")));
    configuration.setLazyLoadTriggerMethods(stringSetValueOf(props.getProperty("lazyLoadTriggerMethods"), "equals,clone,hashCode,toString"));
    configuration.setSafeResultHandlerEnabled(booleanValueOf(props.getProperty("safeResultHandlerEnabled"), true));
    configuration.setDefaultScriptingLanguage(resolveClass(props.getProperty("defaultScriptingLanguage")));
    configuration.setDefaultEnumTypeHandler(resolveClass(props.getProperty("defaultEnumTypeHandler")));
    configuration.setCallSettersOnNulls(booleanValueOf(props.getProperty("callSettersOnNulls"), false));
    configuration.setUseActualParamName(booleanValueOf(props.getProperty("useActualParamName"), true));
    configuration.setReturnInstanceForEmptyRow(booleanValueOf(props.getProperty("returnInstanceForEmptyRow"), false));
    configuration.setLogPrefix(props.getProperty("logPrefix"));
    configuration.setConfigurationFactory(resolveClass(props.getProperty("configurationFactory")));
}

3.解析mapper的xml文件
进入XMLMapperBuilder#parse(),代码如下:

public void parse() {
    if (!configuration.isResourceLoaded(resource)) {
      /*代码在下面分析*/
      configurationElement(parser.evalNode("/mapper"));
      //把当前的mapper文件加到Configuration#loadedResources的set中,代表已经加载过
      configuration.addLoadedResource(resource);
      /* 把当前解析的mapper对应的class加到MapperRegistry#knownMappers的成员中,key是Class对象,value是MapperProxyFactory类型,这个MapperProxyFactory是直接new出来的泛型类对象,泛型指向mapper文件对应的Class接口类型,比如xxx.UserMapper.然后调用MapperAnnotationBuilder#parse()方法解析Mapper文件对应的Class接口中的每个方法上面的注解。这种在接口方法上面通过注解写sql语句的方法比较少用,不方便.*/
      bindMapperForNamespace();
    }
    //解析之前不完整的ResultMap标签,示例代码没有
    parsePendingResultMaps();
    //解析之前不完整的cacheref标签,示例代码没有
    parsePendingCacheRefs();
    //解析之前不完整的statement语句,示例代码没有
    parsePendingStatements();
}

解析mapper文件标签

private void configurationElement(XNode context) {
    try {
      //获取namespace,比如com.xx.UserMapper接口,成员方法对应xml的每个sql语句
      String namespace = context.getStringAttribute("namespace");
      if (namespace == null || namespace.equals("")) {
        throw new BuilderException("Mapper's namespace cannot be empty");
      }
      builderAssistant.setCurrentNamespace(namespace);
      //解析cache-ref标签到Configuration#cacheRefMap中
      cacheRefElement(context.evalNode("cache-ref"));
      //解析cache缓存标签到Configuration#caches成员中.
      cacheElement(context.evalNode("cache"));
      //解析parameterMap标签到Configuration#parameterMaps成员中.
      parameterMapElement(context.evalNodes("/mapper/parameterMap"));
      /*resultMap代表damain对象中字段,类型和数据库列的一一映射关系.解析到Configuration#resultMaps成员map中,key是id,value是个ResultMap类.这个类的成员在下面4给出.*/
      resultMapElements(context.evalNodes("/mapper/resultMap"));
      /*遍历所有的sql片段语句到XMLMapperBuilder#sqlFragments的map中.key是sql的id.value是XNode格式.*/
      sqlElement(context.evalNodes("/mapper/sql"));
      /*遍历所有的sql语句,解析到Configuration#mappedStatements的map中,key是id,value是MappedStatement类,代表一个sql语句,它的类成员在后面4给出.*/
      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);
    }
}

4.存储xml标签和sql语句的一些数据类.
ResultMap类,代表domain对象和数据库表的列的映射关系,代码如下:

public class ResultMap {
  private Configuration configuration;

  private String id;
  private Class<?> type;
  private List<ResultMapping> resultMappings;
  private List<ResultMapping> idResultMappings;
  private List<ResultMapping> constructorResultMappings;
  private List<ResultMapping> propertyResultMappings;
  private Set<String> mappedColumns;
  private Set<String> mappedProperties;
  private Discriminator discriminator;
  private boolean hasNestedResultMaps;
  private boolean hasNestedQueries;
  private Boolean autoMapping;
}

代表一个mapper中select|insert|update|delete的sql语句的类.代码如下:

public final class MappedStatement {
  //xml文件的全路径
  private String resource;
  private Configuration configuration;
  //sql语句的全路径,比如com.xxx.UserMapper.selectByExample
  private String id;
  private Integer fetchSize;
  private Integer timeout;
  /*语句类型,枚举值enum StatementType {
  		STATEMENT, PREPARED, CALLABLE
	}, 默认是PREPARED枚举*/
  private StatementType statementType;
  //默认是Default枚举
  private ResultSetType resultSetType;
  //原始的sql语句,默认是DynamicSqlSource类型,内有SqlNode类型的rootSqlNode成员存储sql语句.在后面给出SqlNode类成员.
  private SqlSource sqlSource;
  private Cache cache;
  private ParameterMap parameterMap;
  private List<ResultMap> resultMaps;
  private boolean flushCacheRequired;
  private boolean useCache;
  private boolean resultOrdered;
  /*sql命令类型,枚举值 enum SqlCommandType {
  		UNKNOWN, INSERT, UPDATE, DELETE, SELECT, FLUSH;
	}
	*/
  private SqlCommandType sqlCommandType;
  private KeyGenerator keyGenerator;
  private String[] keyProperties;
  private String[] keyColumns;
  private boolean hasNestedResultMaps;
  private String databaseId;
  private Log statementLog;
  private LanguageDriver lang;
  private String[] resultSets;
}

存储Sql语句的递归结构

public class MixedSqlNode implements SqlNode {
  private final List<SqlNode> contents;
}

 

二.通过DefaultSqlSessionFactory类获取到mapper接口的代理类.


1.DefaultSqlSessionFactory#openSession()获取SqlSession对象.进入DefaultSqlSessionFactory#openSessionFromDataSource()方法创建SqlSession.代码如下:

参数ExecutorType是枚举类型,默认是SIMPLE.

public enum ExecutorType {
  SIMPLE, REUSE, BATCH
}

参数TransactionIsolationLevel隔离级别也是枚举.

public enum TransactionIsolationLevel {
  NONE(Connection.TRANSACTION_NONE),
  READ_COMMITTED(Connection.TRANSACTION_READ_COMMITTED),
  READ_UNCOMMITTED(Connection.TRANSACTION_READ_UNCOMMITTED),
  REPEATABLE_READ(Connection.TRANSACTION_REPEATABLE_READ),
  SERIALIZABLE(Connection.TRANSACTION_SERIALIZABLE);
}
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      //获取xml文件中配置的jdbc连接参数.
      final Environment environment = configuration.getEnvironment();
      //获取事务工厂为JdbcTransactionFactory类
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      //创建一个Transaction事务对象,jdbc的为JdbcTransaction.类成员在后面2给出
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      //默认创建SimpleExecutor执行器.作为CachingExecutor缓存执行器的成员,委托模式.
      //如果有Interceptor,在这里InterceptorChain#interceptors成员添加拦截这个CachingExecutor执行器.
      final Executor executor = configuration.newExecutor(tx, execType);
      //创建DefaultSqlSession对象返回,DefaultSqlSession成员在后面2给出
      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.Jdbc事务对象

public class JdbcTransaction implements Transaction {
  //事务所在连接
  protected Connection connection;
  //数据源,连接的数据库地址,密码等
  protected DataSource dataSource;
  //事务隔离级别
  protected TransactionIsolationLevel level;
  //默认为false,不自动提交
  protected boolean autoCommit;
}

默认的Sql会话类

public class DefaultSqlSession implements SqlSession {
  private final Configuration configuration;
  //执行器,默认CachingExecutor中引用SimpleExecutor.
  private final Executor executor;
  //默认为false
  private final boolean autoCommit;
  private boolean dirty;
  private List<Cursor<?>> cursorList;
}

3.通过DefaultSqlSession获取mapper接口的代理类
进入DefaultSqlSession#getMapper(),参数为xxx.UserMapper的接口Class.实际调用成员Configuration#mapperRegistry的getMapper方法,mapperRegistry的填充在前面一.3中分析了.MapperRegistry#knownMappers的key是Class对象,value是MapperProxyFactory类型,这个MapperProxyFactory是直接new出来的泛型类对象,泛型指向mapper文件对应的Class接口类型,比如xxx.UserMapper代码如下:

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
	//获取MapperProxyFactory泛型类.
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
      //创建mapper接口的代理对象,代码如下所示
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
}
public T newInstance(SqlSession sqlSession) {
	//MapperProxy实现了InvocationHandler接口,是代理类,所有这个mapper的sql语句都调用它的invoke方法
    final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
    //代码在下面,调用Proxy.newProxyInstance创建代理类,代理类调用MapperProxy类.
    return newInstance(mapperProxy);
}

创建动态代理

protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}

mapper接口代理类

public class MapperProxy<T> implements InvocationHandler, Serializable {
  private final SqlSession sqlSession;
  //代理的mapper接口
  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethod> methodCache;

  //sql语句代理方法
   @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      //代理类的常规想法,去掉Object的方法
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      } else if (isDefaultMethod(method)) {
        //如果是静态,abstract方法,调用原对象
        return invokeDefaultMethod(proxy, method, args);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
    /*取出缓存MapperProxy#methodCache中的MapperMethod对象,开始是空的.创建MapperMethod对象后放进去,MapperMethod类成员下面给出*/
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    //执行sql语句
    return mapperMethod.execute(sqlSession, args);
  }
}
public class MapperMethod {
  //方法对应的sql命令,包含方法名全路径,方法类型
  private final SqlCommand command;
  //方法签名,在下面给出类成员
  private final MethodSignature method;
}

方法签名类

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

 

三.通过mapper接口的代理类执行sql语句.


1.比如执行Employee employee = employeeMapper.selectByPrimaryKey(id)语句.
通过上面二.3的最后分析,进入MapperProxy#invoke()方法,调用MapperMethod#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:
      	//根据select的返回多条记录,一条记录,还是map等调用不同方法.
        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 {
          //上面的selectByPrimaryKey(id)测试代码进入这里.
          //把传进来的sql语句的参数转成Map<String, Object>类型的param
          Object param = method.convertArgsToSqlCommandParam(args);
          //执行sql查询,测试代码进入DefaultSqlSession#selectOne()方法,代码在后面2处分析,策略模式
          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;
}

2.select类型的sql查询
如果只返回一条记录,进入DefaultSqlSession#selectOne().调用DefaultSqlSession#selectList(),代码如下:

public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
      /* 取出xml填充到Configuration#mappedStatements中的sql语句.这个填充过程在前面一.3处分析过了.MappedStatement类成员代码在前面的一.4中有。具体的sql语句在MappedStatement#sqlSource成员中递归存储*/
      MappedStatement ms = configuration.getMappedStatement(statement);
      //调用CachingExecutor#query(),代码在下面分析
      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();
    }
}

缓存执行器执行查询CachingExecutor#query(),代码如下:

public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
	//创建动态sql
    BoundSql boundSql = ms.getBoundSql(parameterObject);
    //缓存sql语句,key为为xml中的sql语句id+offset+limit+sql语句
    CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
    //调用代码在下面
    return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

动态sql类BoundSql成员,里面有?,#{id}等占位符

public class BoundSql {
  //存放字符串形式的具体的sql语句
  private final String sql;
  private final List<ParameterMapping> parameterMappings;
  private final Object parameterObject;
  private final Map<String, Object> additionalParameters;
  private final MetaObject metaParameters;
}

缓存执行器执行查询CachingExecutor#query(),代码如下:

public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
      throws SQLException {
    Cache cache = ms.getCache();
    //如果有缓存的结果,从缓存中取结果
    if (cache != null) {
      flushCacheIfRequired(ms);
      if (ms.isUseCache() && resultHandler == null) {
        ensureNoOutParams(ms, boundSql);
        @SuppressWarnings("unchecked")
        List<E> list = (List<E>) tcm.getObject(cache, key);
        if (list == null) {
          list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
          tcm.putObject(cache, key, list); // issue #578 and #116
        }
        return list;
      }
    }
    /* 没有缓存,调用BaseExecutor#query()方法执行,进入BaseExecutor#queryFromDatabase(),代码在下面分析*/
    return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

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 {
      //调用SimpleExecutor#doQuery()执行查询.在后面的3处分析
      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;
}

3. 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();
      /* 创建RoutingStatementHandler执行sql.加入StatementHandler的目的是用来区分StatementType枚举的三种调用STATEMENT, PREPARED, CALLABLE.如下面的RoutingStatementHandler类的构造方法所示,每种枚举对应不同的StatementHandler*/
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      //调用SimpleExecutor#prepareStatement()准备sql语句,准备过程在下面分析
      stmt = prepareStatement(handler, ms.getStatementLog());
      //调用jdbc执行sql查询,代码在后面分析
      return handler.query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
}

RoutingStatementHandler创建不同的种类的StatementHandler.内部成员delegate委托模式具体执行sql语句.
 

public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, 		ResultHandler resultHandler, BoundSql boundSql) {
    switch (ms.getStatementType()) {
      case STATEMENT:
        delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case PREPARED:
      	//默认是预编译类型的语句处理器
        delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case CALLABLE:
        delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      default:
        throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
    }
}

准备sql语句,进入SimpleExecutor#prepareStatement()
 

private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    Statement stmt;
    //调用JdbcTransaction#openConnection(),进入javax.sql.DataSource#getConnection()获取数据库连接
    Connection connection = getConnection(statementLog);
    //处理sql语句的占位符
    stmt = handler.prepare(connection, transaction.getTimeout());
    handler.parameterize(stmt);
    return stmt;
}

调用jdbc执行sql查询,向mysql通过socket发出sql语句.进入SimpleStatementHandler#query,如下代码所示:
 

@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    String sql = boundSql.getSql();
    //调用jdbc的方法java.sql.Statement#execute(java.lang.String)执行sql语句
    statement.execute(sql);
    return resultSetHandler.handleResultSets(statement);
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值