Mybatis源码解析-执行流程(旧)

有时候,不是因为你没有能力,也不是因为你缺少勇气,只是因为你付出的努力还太少,所以,成功便不会走向你。而你所需要做的,就是坚定你的梦想,你的目标,你的未来,然后以不达目的誓不罢休的那股劲,去付出你的努力,成功就会慢慢向你靠近。

导读:本篇文章讲解 Mybatis源码解析-执行流程(旧),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

一、准备工作

mybatis版本:3.5.2

public class Client {
    @Test
    public void selectUser() throws IOException {
        //初始化参数,获取连接
        String resource = "mybatis-config.xml";
        InputStream inputStream = getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //获取接口反射对象
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        User user = userDao.getUserById(1);
        System.out.println(user);
        sqlSession.close();
    }
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING" />
    </settings>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/school?serverTimezone=UTC&amp;useUnicode=true&amp;characterEncoding=utf8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/xc/dao/UserMapper.xml"/>
    </mappers>
</configuration>

二、SqlSessionFactory初始化

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

1)创建SqlSessionFactoryBuilder

建造者模式,SqlSessionFactoryBuilder 类中都是通过不同的入参重载方法返回SqlSessionFactory

public class SqlSessionFactoryBuilder {
	//创建SqlSessionFactoryBuilder对象
    public SqlSessionFactoryBuilder() {
    }
    //调用build一个入参的方法
    public SqlSessionFactory build(InputStream inputStream) {
    	//再调用build三个入参的重载方法
        return this.build((InputStream)inputStream, (String)null, (Properties)null);
    }
    public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
        SqlSessionFactory var5;
        try {
        	//创建XMLConfigBuilder对象
            XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
            //解析mybatis配置文件
            var5 = this.build(parser.parse());
        } catch (Exception var14) {
            throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
        } finally {
            ErrorContext.instance().reset();
            try {
                inputStream.close();
            } catch (IOException var13) {
            }
        }
        return var5;
    }
}

2)创建XMLConfigBuilder对象,根据配置文件输入流创建Document对象

public class XMLConfigBuilder extends BaseBuilder {
  private boolean parsed;
  //xml解析器
  private final XPathParser parser;
  private String environment;
  private final ReflectorFactory localReflectorFactory = new DefaultReflectorFactory();
  //重载方法之间的调用
  public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
  	//xml解析器根据配置文件流创建Document对象
    this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
  }
  //具体逻辑
  private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
  	//创建Configuration对象,注册乱七八糟的别名
    super(new Configuration());
    ErrorContext.instance().resource("SQL Mapper Configuration");
    this.configuration.setVariables(props);
    this.parsed = false;
    this.environment = environment;
    this.parser = parser;
  }
}

3)解析mybatis配置文件,封装到Configuration对象中

public class XMLConfigBuilder extends BaseBuilder {
  //默认设置为false
  public Configuration parse() {
    if (parsed) {
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    //只解析一次,Configuration配置文件是全局的,只能被解析一次
    parsed = true;
    //获取根节点configuration
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
  }
  //解析根节点configuration下的子节点
  private void parseConfiguration(XNode root) {
    try {
      //解析properties元素
      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);
      //解析environment元素
      environmentsElement(root.evalNode("environments"));
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      typeHandlerElement(root.evalNode("typeHandlers"));
      //解析mappers元素
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }
}

解析properties元素

private void propertiesElement(XNode context) throws Exception {
  if (context != null) {
  	//将properties配置文件的name和value属性set到Properties对象
    Properties defaults = context.getChildrenAsProperties();
    String resource = context.getStringAttribute("resource");
    String url = context.getStringAttribute("url");
    if (resource != null && url != null) {
      throw new BuilderException("The properties element cannot specify both a URL and a resource based property file reference.  Please specify one or the other.");
    }
    //将配置文件资源信息放入Properties对象
    if (resource != null) {
      defaults.putAll(Resources.getResourceAsProperties(resource));
    } else if (url != null) {
      defaults.putAll(Resources.getUrlAsProperties(url));
    }
    Properties vars = configuration.getVariables();
    if (vars != null) {
      defaults.putAll(vars);
    }
    parser.setVariables(defaults);
    //最后放入configuation对象中
    configuration.setVariables(defaults);
  }
}

解析environment(环境)元素

private void environmentsElement(XNode context) throws Exception {
  if (context != null) {
    if (environment == null) {
       //解析environments节点的default属性的值
      //例如: <environments default="dev">
      environment = context.getStringAttribute("default");
    }
    //递归解析environments子节点
    for (XNode child : context.getChildren()) {
	  /*
		<environments default="dev">
			<environment id="test">... </environment>
			<environment id="dev">... </environment>
        </environments>
	  */
	  //通过default默认选择dev环境还是test环境,切换环境
      String id = child.getStringAttribute("id");
      //isSpecial就是根据由environments的default属性去选择对应的enviroment
      if (isSpecifiedEnvironment(id)) {
        //事务
        TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
        //数据源
        DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
        DataSource dataSource = dsFactory.getDataSource();
        Environment.Builder environmentBuilder = new Environment.Builder(id)
            .transactionFactory(txFactory)
            .dataSource(dataSource);
        //创建environment对象放入configuration对象里
        configuration.setEnvironment(environmentBuilder.build());
      }
    }
  }
}

解析mappers元素

private void mapperElement(XNode parent) throws Exception {
  if (parent != null) {
    for (XNode child : parent.getChildren()) {
      if ("package".equals(child.getName())) {
      	//包扫描方式
        String mapperPackage = child.getStringAttribute("name");
        configuration.addMappers(mapperPackage);
      } else {
      	//路径加载方法
        String resource = child.getStringAttribute("resource");
        String url = child.getStringAttribute("url");
        String mapperClass = child.getStringAttribute("class");
        if (resource != null && url == null && mapperClass == null) {
          ErrorContext.instance().resource(resource);
          InputStream inputStream = Resources.getResourceAsStream(resource);
          //创建mappersxml对象XMLMapperBuilder
          XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
          //解析XMLMapperBuilder
          mapperParser.parse();
        } else if (resource == null && url != null && mapperClass == null) {
          ErrorContext.instance().resource(url);
          InputStream inputStream = Resources.getUrlAsStream(url);
          XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
          mapperParser.parse();
        } else if (resource == null && url == null && mapperClass != null) {
          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.");
        }
      }
    }
  }
}

解析XMLMapperBuilder

public void parse() {
  // 判断是否已经加载过
  if (!configuration.isResourceLoaded(resource)) {
  	// 解析 <mapper> 节点
    configurationElement(parser.evalNode("/mapper"));
    // 标记一下,已经加载过了
    configuration.addLoadedResource(resource);
    // 绑定映射器到namespace
    bindMapperForNamespace();
  }
  // 处理 configurationElement 中解析失败的<resultMap>
  parsePendingResultMaps();
  // 处理configurationElement 中解析失败的<cache-ref>
  parsePendingCacheRefs();
  // 处理 configurationElement 中解析失败的 SQL 语句
  parsePendingStatements();
}

解析 节点

private void configurationElement(XNode context) {
  try {
    // 获取namespace属性, 其代表者这个文档的标识
    String namespace = context.getStringAttribute("namespace");
    if (namespace == null || namespace.equals("")) {
      throw new BuilderException("Mapper's namespace cannot be empty");
    }
    builderAssistant.setCurrentNamespace(namespace);
    // 解析 <cache-ref> 节点
    cacheRefElement(context.evalNode("cache-ref"));
    // 解析 <cache> 节点
    cacheElement(context.evalNode("cache"));
    // 解析 </mapper/parameterMap> 节点
    parameterMapElement(context.evalNodes("/mapper/parameterMap"));
    // 解析 </mapper/resultMap> 节点
    resultMapElements(context.evalNodes("/mapper/resultMap"));
    // 解析 </mapper/sql> 节点
    sqlElement(context.evalNodes("/mapper/sql"));
    // 解析 select|insert|update|delet 节点
    buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
  } catch (Exception e) {
    throw new BuilderException("Error parsing Mapper XML. Cause: " + e, e);
  }
}

解析 select | insert | update | delet 节点

private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
  for (XNode context : list) {
  	//创建XMLStatementBuilder对象
    final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
    try {
      //解析对象
      statementParser.parseStatementNode();
    } catch (IncompleteElementException e) {
      configuration.addIncompleteStatement(statementParser);
    }
  }
}

将获取到的所有属性添加到addMappedStatement方法中,之后会生成MappedStatement对象

public void parseStatementNode() {
...
  SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
  StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
  Integer fetchSize = context.getIntAttribute("fetchSize");
  Integer timeout = context.getIntAttribute("timeout");
  String parameterMap = context.getStringAttribute("parameterMap");
  String resultType = context.getStringAttribute("resultType");
  Class<?> resultTypeClass = resolveClass(resultType);
  String resultMap = context.getStringAttribute("resultMap");
  String resultSetType = context.getStringAttribute("resultSetType");
  ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);
  if (resultSetTypeEnum == null) {
    resultSetTypeEnum = configuration.getDefaultResultSetType();
  }
  String keyProperty = context.getStringAttribute("keyProperty");
  String keyColumn = context.getStringAttribute("keyColumn");
  String resultSets = context.getStringAttribute("resultSets");
  //将获取到的所有属性添加到此方法
  builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
      fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
      resultSetTypeEnum, flushCache, useCache, resultOrdered,
      keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
}

将select|insert|update|delete标签属性放入MappedStatement 对象
在这里插入图片描述

bindMapperForNamespace(); 绑定映射器到namespace
knownMappers是一个map,key为接口Class对象,value为MapperProxyFaxtory工厂
MapperProxyFaxtory工厂,最终会通过此工厂创建UserDao的代理对象
在这里插入图片描述

4)将Configuration对象包装到DefaultSqlSessionFactory对象属性中

public SqlSessionFactory build(Configuration config) {
  return new DefaultSqlSessionFactory(config);
}

则SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
生成的SqlSessionFactory工厂的具体实现为DefaultSqlSessionFactory

对象Configuration 属性如下
在这里插入图片描述

  • environment:环境对象,包含数据库连接信息
  • defaultExecutorType:后续执行sql的执行器;SIMPLE普通增删改查,还有批量执行器,存储过程执行器
  • mapperRegistry:namespace绑定的接口。key:接口Class对象,value:接口信息,后续生成代理对象
  • interceptorChain:拦截器,后续在四大对象中使用
  • typeHandlerRegistry:数据库和java的数据类型转换器
  • typeAliasRegistry:mapper文件中的默认别名设置
  • mappedStatements:key:具体方法名,value:MappedStatement对象,关于方法sql、参数等等所有信息

三、获取SqlSession对象

1)SqlSession sqlSession = sqlSessionFactory.openSession()

public class DefaultSqlSessionFactory implements SqlSessionFactory {
  @Override
  public SqlSession openSession() {
  	//设置执行性为默认的SIMPLE
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), 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);
	    //生成SqlSession
	    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)创建普通执行器

public class Configuration {
  public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    executorType = executorType == null ? defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    Executor executor;
    if (ExecutorType.BATCH == executorType) {
      executor = new BatchExecutor(this, transaction);
    } else if (ExecutorType.REUSE == executorType) {
      executor = new ReuseExecutor(this, transaction);
    } else {
      executor = new SimpleExecutor(this, transaction);
    }
    //二级缓存全局开关,默认开启。具体使用还需要在mapperxml中添加 <cache />
    if (cacheEnabled) {
      executor = new CachingExecutor(executor);
    }
    //执行拦截器,重新包装执行器返回
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
  }
}

使用CachingExecutor执行器好处,在每次查询前先查询缓存数据,使用装饰者模式,将查询方法包装在内。

3)根据configuration、executor等信息获取DefaultSqlSession**

 public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
   this.configuration = configuration;
   this.executor = executor;
   this.dirty = false;
   this.autoCommit = autoCommit;
 }

四、getMapper获取接口的代理对象

1)UserDao userDao = sqlSession.getMapper(UserDao.class)

实现SqlSesion接口的getMapper方法

public class DefaultSqlSession implements SqlSession {
  @Override
  public <T> T getMapper(Class<T> type) {
    return configuration.getMapper(type, this);
  }
}

调用配置类getMapper方法

public class Configuration {
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
  }
}
public class MapperRegistry {
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
  	//根据sqlSessionFactory工厂初始化 knownMappers key:接口Class,value:接口信息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 {
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }
}

2)Proxy.newProxyInstance动态代理获取接口代理对象

public class MapperProxyFactory<T> {

  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<>();

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

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

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

  @SuppressWarnings("unchecked")
  protected T newInstance(MapperProxy<T> mapperProxy) {
     /**
    * 1.指定当前目标对象使用的类加载器
    * 2.目标对象实现的接口类型
    * 3.事情处理,执行目标对象方法时,会触发事情处理器方法(会把当前执行的目标对象方法作为参数传入)
    */
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

  public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }
}

mapperProxy的MapperProxy类实现了InvocationHandler接口,具体触发事件在invoke内,具体下面讲。

五、查询流程

1)User user = userDao.getUserById(1);进入动态代理invoke方法

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      //判断是否Object对象里toString,hashcode等方法,执行默认invoke
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      } else if (method.isDefault()) {
        return invokeDefaultMethod(proxy, method, args);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
    //将method包装为MapperMethod方法
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    //执行方法
    return mapperMethod.execute(sqlSession, args);
  }

MapperMethod 对象,包含sql类型,方法路径,返回值等信息
在这里插入图片描述

2)执行MapperMethod 类执行方法

public class MapperMethod {
  public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    //判断sql类型,增删改查
    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);
        //返回map
        } else if (method.returnsMap()) {
          result = executeForMap(sqlSession, args);
        } else if (method.returnsCursor()) {
          result = executeForCursor(sqlSession, args);
        } else {
          //返回一个
          //封装参数,将参数放入map中,并指定key
          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;
  }
}

selectOne方法,调用selectList方法,返回多个报错

public class DefaultSqlSession implements SqlSession {
  @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;
    }
  }
  @Override
  public <E> List<E> selectList(String statement, Object parameter) {
    return this.selectList(statement, parameter, RowBounds.DEFAULT);
  }
  //selectList方法具体实现
  @Override
  public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
      //根据方法名全类名字符串获取MappedStatemets对象,configuration对象初始化时生成
      MappedStatement ms = configuration.getMappedStatement(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();
    }
  }
}

3)执行器sql方法

wrapCollection(parameter) 方法
设置参数map的默认值,集合key为list,数组key为array

private Object wrapCollection(final Object object) {
  if (object instanceof Collection) {
    StrictMap<Object> map = new StrictMap<>();
    map.put("collection", object);
    if (object instanceof List) {
      map.put("list", object);
    }
    return map;
  } else if (object != null && object.getClass().isArray()) {
    StrictMap<Object> map = new StrictMap<>();
    map.put("array", object);
    return map;
  }
  return object;
}

缓存执行器

public class CachingExecutor implements Executor {
  @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);
  }
}

绑定sql包含sql语句,每个占位符字段类型,具体的值value
在这里插入图片描述
创建缓存key = 方法名+sql语句+参数类型+参数值+额外参数
在这里插入图片描述
查询方法

@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
    throws SQLException {
  //获取此mappserxml是否开启二级缓存
  Cache cache = ms.getCache();
  if (cache != null) {
  	//是否设置刷新
    flushCacheIfRequired(ms);
    if (ms.isUseCache() && resultHandler == null) {
      ensureNoOutParams(ms, boundSql);
      @SuppressWarnings("unchecked")
      //根据key查缓存,如果查不到。查询数据库,并把结果放入二级缓存
      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;
    }
  }
  //普通执行器的查询方法
  return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

缓存执行器方法执行后执行普通执行器的查询方法

public abstract class BaseExecutor implements Executor {
  @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++;
      //根据key查询本地缓存及一级缓存
      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;
  }
  //具体执行方法
  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 {
      //sql执行方法
      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;
  }
}

sql执行方法

public class SimpleExecutor extends BaseExecutor {
  @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);
      //预编译sql
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }
}

创建PreparedStatementHandler时候,其父类BaseStatementHandler会创建ParameterHandler(预编译sql)和ResultSetHandler(封装结果集)

public class RoutingStatementHandler implements StatementHandler {

  private final StatementHandler delegate;

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

  }
}

StatementHandler对象,拦截器,包装重新返回

public class Configuration {
  public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
    return statementHandler;
  }
}

configuration.newStatementHandler创建StatementHandler(Statement处理器)
生成PreparedStatementHandler,预编译属性
在这里插入图片描述
预编译sql

public class SimpleExecutor extends BaseExecutor {
  private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    Statement stmt;
    //获取连接
    Connection connection = getConnection(statementLog);
    //预编译
    stmt = handler.prepare(connection, transaction.getTimeout());
    handler.parameterize(stmt);
    return stmt;
  }
}

进入PreparedStatementHandler的prepare,调用基类的方法

public abstract class BaseStatementHandler implements StatementHandler {
  @Override
  public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
    ErrorContext.instance().sql(boundSql.getSql());
    Statement statement = null;
    try {
      //实例化Statement
      statement = instantiateStatement(connection);
      //设置超时
      setStatementTimeout(statement, transactionTimeout);
      //设置读取条数
      setFetchSize(statement);
      return statement;
    } catch (SQLException e) {
      closeStatement(statement);
      throw e;
    } catch (Exception e) {
      closeStatement(statement);
      throw new ExecutorException("Error preparing statement.  Cause: " + e, e);
    }
  }
}

而instantiateStatement是基类留给子类去实现,所有调用PreparedStatementHandler的instantiateStatement
这里就是jdbc的代码,connection.prepareStatement创建PrepareStatement对象

public class PreparedStatementHandler extends BaseStatementHandler {
  @Override
  protected Statement instantiateStatement(Connection connection) throws SQLException {
    String sql = boundSql.getSql();
    if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
      String[] keyColumnNames = mappedStatement.getKeyColumns();
      if (keyColumnNames == null) {
        return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
      } else {
        return connection.prepareStatement(sql, keyColumnNames);
      }
    } else if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
      return connection.prepareStatement(sql);
    } else {
      return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
    }
  }
}

预编译就是将sql变成一个函数,函数的变量用占位符表示,后面注入的参数系统默认它仅仅是一个参数,而不会认为是一个sql语句,不会再次编译。

4)ParameterHandler

handler.parameterize(stmt);

public class DefaultParameterHandler implements ParameterHandler {
  @Override
  public void setParameters(PreparedStatement ps) {
    ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
    List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
    if (parameterMappings != null) {
      //循环设参数
      for (int i = 0; i < parameterMappings.size(); i++) {
        ParameterMapping parameterMapping = parameterMappings.get(i);
        if (parameterMapping.getMode() != ParameterMode.OUT) {
          Object value;
          String propertyName = parameterMapping.getProperty();
          if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
            value = boundSql.getAdditionalParameter(propertyName);
          } else if (parameterObject == null) {
            value = null;
          } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
            value = parameterObject;
          } else {
            MetaObject metaObject = configuration.newMetaObject(parameterObject);
            value = metaObject.getValue(propertyName);
          }
          TypeHandler typeHandler = parameterMapping.getTypeHandler();
          JdbcType jdbcType = parameterMapping.getJdbcType();
          if (value == null && jdbcType == null) {
            //不同类型的set方法不同,委派给子类的setParameter方法
            jdbcType = configuration.getJdbcTypeForNull();
          }
          try {
            typeHandler.setParameter(ps, i + 1, value, jdbcType);
          } catch (TypeException | SQLException e) {
            throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
          }
        }
      }
    }
  }

}

5)TypeHandler接口

类型处理器接口,它在ParameterHandler和ResultSetHandler都用到,用于对类型的转换。
举个例子,比如String

public class StringTypeHandler extends BaseTypeHandler<String> {

  @Override
  public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType)
      throws SQLException {
    ps.setString(i, parameter);
  }

  @Override
  public String getNullableResult(ResultSet rs, String columnName)
      throws SQLException {
    return rs.getString(columnName);
  }
}

在ParamterHandler中,使用setParameter方法,它用于将传入的parameter设置成数据库的类型
在ResultSetHandler中,使用getResult方法,它用于将数据库类型转换为返回值的类型

6)ResultSetHandler

https://zoyi14.smartapps.cn/pages/note/index?slug=ec2894eff3ad&origin=userPage&_swebfr=1&_swebFromHost=baiduboxapp

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/148670.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!