找回密码
 立即注册
首页 业界区 业界 1.Java Mybatis框架源码分析

1.Java Mybatis框架源码分析

炳裘垦 2025-7-6 20:00:39
目录

  • 1. 使用

    • 1.1. 新建maven项目
    • 1.2. pom.xml
    • 1.3. 配置mybatis
    • 1.4. 新建mapper
    • 1.5. 测试
    • 1.6. 项目结构

  • 2. 源码分析

    • 2.1. 框架分层
    • 2.2. 四大对象
    • 2.3. 要分析的代码
    • 2.4. 获取SqlSessionFactory对象

      • 2.4.1. 解析xml配置

        • 2.4.1.1. 解析mybatis全局配置
        • 2.4.1.2. 解析mapper.xml


    • 2.5. 获取sqlsession对象

      • 2.5.1. 获取数据库链接信息
      • 2.5.2. 创建事务管理工厂
      • 2.5.3. 创建Executor

        • 2.5.3.1. Executor继承体系


    • 2.6. 获取mapper类的代理对象

      • 2.6.1. 从MapperRegistry通过mapper名获取MapperProxyFactory
      • 2.6.2. 通过MapperProxyFactory使用jdk动态代理创建mapper

    • 2.7. 通过代理对象执行CRUD方法

      • 2.7.1. 通过MapperMethod执行sql
      • 2.7.2. 怎么执行sql的

        • 2.7.2.1. 把sql语句封装成MappedStatement
        • 2.7.2.2. 通过Executor执行sql

          • 2.7.2.2.1. 二级缓存中有则直接返回
          • 2.7.2.2.2. 一级缓存中有则直接返回,没有在查数据库
          • 2.7.2.2.3. 真正的jdbc操作




  • 3. 参考

1. 使用

1.1. 新建maven项目


1.2. pom.xml
  1.     4.0.0    com.zsk    mybatis_test    1.0-SNAPSHOT            UTF-8        1.8        1.8        1.8                            org.mybatis            mybatis            3.5.3                            org.postgresql            postgresql            42.2.8                                                    org.apache.maven.plugins                maven-compiler-plugin                3.7.0                                                                src/main/java                                    **/*.*                                                        src/main/resources                                    **/*.*                                                                                    src/main/webapp                                META-INF/resources                                    **/*.*                                false                        
复制代码
1.3. 配置mybatis


  • resources/jdbc.properties
  1. driver=org.postgresql.Driverurl=jdbc:postgresql://localhost:5432/taousername=zskpassword=zskroot
复制代码

  • resources/mybatis-config.xml
  1.                                                                                                                                                 
复制代码
1.4. 新建mapper


  • com.zsk.model.User
  1. package com.zsk.model;/** * @description: * @author: zsk * @create: 2019-11-30 15:32 **/public class User{    private Long id;    private String username;    public Long getId()    {        return id;    }    public void setId(Long id)    {        this.id = id;    }    public String getUsername()    {        return username;    }    public void setUsername(String username)    {        this.username = username;    }    @Override    public String toString()    {        return "User{" + "id=" + id + ", username='" + username + '\'' + '}';    }}
复制代码

  • com.zsk.dao.UserMapper
  1. package com.zsk.dao;import com.zsk.model.User;/** * @description: * @author: zsk * @create: 2019-11-30 15:31 **/public interface UserMapper{    User getById(Long id);}
复制代码

  • mapper/UserMapper.xml
  1.             select * from tb_user where id = #{id}   
复制代码
1.5. 测试


  • Main
  1. import com.zsk.dao.UserMapper;import com.zsk.model.User;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.IOException;import java.io.InputStream;/** * @description: * @author: zsk * @create: 2019-11-30 15:28 **/public class Main{    public static void main(String[] args) throws IOException    {        String resource = "mybatis-config.xml";        InputStream inputStream = Resources.getResourceAsStream(resource);        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);        try (SqlSession session = sqlSessionFactory.openSession())        {            UserMapper mapper = session.getMapper(UserMapper.class);            User user = mapper.getById(7L);            System.out.println(user);        }    }}
复制代码
1.6. 项目结构


2. 源码分析


目录

  • 1. 使用

    • 1.1. 新建maven项目
    • 1.2. pom.xml
    • 1.3. 配置mybatis
    • 1.4. 新建mapper
    • 1.5. 测试
    • 1.6. 项目结构

  • 2. 源码分析

    • 2.1. 框架分层
    • 2.2. 四大对象
    • 2.3. 要分析的代码
    • 2.4. 获取SqlSessionFactory对象

      • 2.4.1. 解析xml配置

        • 2.4.1.1. 解析mybatis全局配置
        • 2.4.1.2. 解析mapper.xml


    • 2.5. 获取sqlsession对象

      • 2.5.1. 获取数据库链接信息
      • 2.5.2. 创建事务管理工厂
      • 2.5.3. 创建Executor

        • 2.5.3.1. Executor继承体系


    • 2.6. 获取mapper类的代理对象

      • 2.6.1. 从MapperRegistry通过mapper名获取MapperProxyFactory
      • 2.6.2. 通过MapperProxyFactory使用jdk动态代理创建mapper

    • 2.7. 通过代理对象执行CRUD方法

      • 2.7.1. 通过MapperMethod执行sql
      • 2.7.2. 怎么执行sql的

        • 2.7.2.1. 把sql语句封装成MappedStatement
        • 2.7.2.2. 通过Executor执行sql

          • 2.7.2.2.1. 二级缓存中有则直接返回
          • 2.7.2.2.2. 一级缓存中有则直接返回,没有在查数据库
          • 2.7.2.2.3. 真正的jdbc操作




  • 3. 参考

2.1. 框架分层


2.2. 四大对象

MyBatis创建四大对象的时候,使用动态代理机制添加了拦截器.

  • Executor
  • ParameterHandler
  • ResultSetHandler
  • StatementHandler
2.3. 要分析的代码
  1. public class Test{    public static void main(String[] args) throws Exception    {        String resource = "mybatis-config.xml";        InputStream inputStream = Resources.getResourceAsStream(resource);        //1.获取SqlSessionFactory对象        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);        //2.获取sqlsession对象        SqlSession session = sqlSessionFactory.openSession();        //3.获取接口的代理对象        TtestMapper mapper = session.getMapper(TtestMapper.class);        //4.执行CRUD方法        Ttest blog = mapper.getOne(1);        System.out.println(blog);        session.close();    }}
复制代码
2.4. 获取SqlSessionFactory对象


  • new SqlSessionFactoryBuilder().build(inputStream)
  1. public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {    try {          //读取mybatis-config.xml,并把配置信息封装到XMLConfigBuilder      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);      //把xml文件中的配置全部封装到Configuraion里面      return build(parser.parse());    } catch (Exception e) {      throw ExceptionFactory.wrapException("Error building SqlSession.", e);    } finally {      ErrorContext.instance().reset();      try {        inputStream.close();      } catch (IOException e) {        // Intentionally ignore. Prefer previous error.      }    }  }
复制代码
2.4.1. 解析xml配置

2.4.1.1. 解析mybatis全局配置


  • XMLConfigBuilder
  1. public Configuration parse() {        //解析过了直接抛出异常    if (parsed) {      throw new BuilderException("Each XMLConfigBuilder can only be used once.");    }    parsed = true;    //通过XPath获取mybatis-config.xml中的configuration节点作为root节点,继续解析下级节点    parseConfiguration(parser.evalNode("/configuration"));    return configuration;  }private void parseConfiguration(XNode root) {    try {      //issue #117 read properties first      propertiesElement(root.evalNode("properties"));      //获取settings节点,封装到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"));      //把settings节点下的所有属性设置到Configuration中      settingsElement(settings);      // read it after objectFactory and objectWrapperFactory issue #631      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);    }  }  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")));  }        private void mapperElement(XNode parent) throws Exception {    if (parent != null) {      for (XNode child : parent.getChildren()) {      //有package节点则走下面的逻辑        if ("package".equals(child.getName())) {          String mapperPackage = child.getStringAttribute("name");          configuration.addMappers(mapperPackage);        } else {          //根据resource,url,class节点确定走那段逻辑          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);            XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());            //解析mapper标签            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对象加载到configuration中            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.");          }        }      }    }  }
复制代码
2.4.1.2. 解析mapper.xml


  • XMLMapperBuilder
  1. public void parse() {    if (!configuration.isResourceLoaded(resource)) {          //mapper标签      configurationElement(parser.evalNode("/mapper"));      configuration.addLoadedResource(resource);      bindMapperForNamespace();    }    parsePendingResultMaps();    parsePendingCacheRefs();    parsePendingStatements();  }  private void configurationElement(XNode context) {        try {          String namespace = context.getStringAttribute("namespace");          if (namespace == null || namespace.equals("")) {                throw new BuilderException("Mapper's namespace cannot be empty");          }                    builderAssistant.setCurrentNamespace(namespace);          cacheRefElement(context.evalNode("cache-ref"));          cacheElement(context.evalNode("cache"));          //解析parameterMap,resultMap,sql标签并存放到Configuration中          parameterMapElement(context.evalNodes("/mapper/parameterMap"));          resultMapElements(context.evalNodes("/mapper/resultMap"));          sqlElement(context.evalNodes("/mapper/sql"));          //解析CRUD标签          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);        }        }        private void buildStatementFromContext(List list) {        if (configuration.getDatabaseId() != null) {          buildStatementFromContext(list, configuration.getDatabaseId());        }        buildStatementFromContext(list, null);}private void buildStatementFromContext(List list, String requiredDatabaseId) {        for (XNode context : list) {          final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);          try {                statementParser.parseStatementNode();          } catch (IncompleteElementException e) {                configuration.addIncompleteStatement(statementParser);          }        }}public void parseStatementNode() {    String id = context.getStringAttribute("id");    String databaseId = context.getStringAttribute("databaseId");    if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {      return;    }    String nodeName = context.getNode().getNodeName();    SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));    boolean isSelect = sqlCommandType == SqlCommandType.SELECT;    boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect);    boolean useCache = context.getBooleanAttribute("useCache", isSelect);    boolean resultOrdered = context.getBooleanAttribute("resultOrdered", false);    // Include Fragments before parsing    XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);    includeParser.applyIncludes(context.getNode());    String parameterType = context.getStringAttribute("parameterType");    Class parameterTypeClass = resolveClass(parameterType);    String lang = context.getStringAttribute("lang");    LanguageDriver langDriver = getLanguageDriver(lang);    // Parse selectKey after includes and remove them.    processSelectKeyNodes(id, parameterTypeClass, langDriver);    // Parse the SQL (pre:  and  were parsed and removed)    KeyGenerator keyGenerator;    String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX;    keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true);    if (configuration.hasKeyGenerator(keyStatementId)) {      keyGenerator = configuration.getKeyGenerator(keyStatementId);    } else {      keyGenerator = context.getBooleanAttribute("useGeneratedKeys",          configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType))          ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;    }    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);    String keyProperty = context.getStringAttribute("keyProperty");    String keyColumn = context.getStringAttribute("keyColumn");    String resultSets = context.getStringAttribute("resultSets");        //最终封装成MappedStatement对象    builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,        fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,        resultSetTypeEnum, flushCache, useCache, resultOrdered,        keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);  }
复制代码


2.5. 获取sqlsession对象


  • DefaultSqlSessionFactory.openSession()
  1. public class DefaultSqlSessionFactory implements SqlSessionFactory {         @Override          public SqlSession openSession() {                  //根据Configuration配置的ExecutorType(默认是SIMPLE)来获取SqlSession            return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);                  }  private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {        Transaction tx = null;        try {                //从Configuration中获取数据库链接信息          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包含了Configuration,Executor信息          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.5.1. 获取数据库链接信息

2.5.2. 创建事务管理工厂

2.5.3. 创建Executor


  • Configuration
  1. public class Configuration {        public Executor newExecutor(Transaction transaction, ExecutorType executorType) {                //默认是ExecutorType.SIMPLE                executorType = executorType == null ? defaultExecutorType : executorType;                executorType = executorType == null ? ExecutorType.SIMPLE : executorType;                Executor executor;                //根据不同的type创建不同的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);                }                //装饰器模式:把原始的Executor用Cache包装                if (cacheEnabled) {                  executor = new CachingExecutor(executor);                }                //也是装饰器模式?--把所有插件都包装到Executor上                executor = (Executor) interceptorChain.pluginAll(executor);                return executor;          }}
复制代码
2.5.3.1. Executor继承体系


2.6. 获取mapper类的代理对象


  • DefaultSqlSession.getMapper(TtestMapper.class)
  1. @Override  public  T getMapper(Class type) {          //调用Configuration的getMapper方法    return configuration.getMapper(type, this);  }
复制代码
2.6.1. 从MapperRegistry通过mapper名获取MapperProxyFactory


  • Configuration
  1. public  T getMapper(Class type, SqlSession sqlSession) {        //调用MapperRegistry(存储了Mapper名:MapperProxyFactory)的getMapper方法    return mapperRegistry.getMapper(type, sqlSession);  }
复制代码

  • MapperRegistry
  1. @SuppressWarnings("unchecked")  public  T getMapper(Class type, SqlSession sqlSession) {          //从Map> knownMappers = new HashMap();获取MapperProxyFactory    final MapperProxyFactory mapperProxyFactory = (MapperProxyFactory) 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.6.2. 通过MapperProxyFactory使用jdk动态代理创建mapper


  • MapperProxyFactory
  1. public T newInstance(SqlSession sqlSession) {         //class MapperProxy implements InvocationHandler,JDK的动态代理接口    final MapperProxy mapperProxy = new MapperProxy(sqlSession, mapperInterface, methodCache);    return newInstance(mapperProxy);  }    @SuppressWarnings("unchecked")  protected T newInstance(MapperProxy mapperProxy) {          //参数:被代理对象的类加载器,被代理对象实现的接口,对立对象实例    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);  }
复制代码
2.7. 通过代理对象执行CRUD方法


  • MapperProxy.getOne(1)
  1. //调用的是代理类的invoke方法 @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)) {        return invokeDefaultMethod(proxy, method, args);      }    } catch (Throwable t) {      throw ExceptionUtil.unwrapThrowable(t);    }    //从缓存中获取MapperMethod    final MapperMethod mapperMethod = cachedMapperMethod(method);    //执行sql语句    return mapperMethod.execute(sqlSession, args);  }   private MapperMethod cachedMapperMethod(Method method) {         //Map中有这个方法的话直接返回,没有则new返回    return methodCache.computeIfAbsent(method, k -> new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));  }
复制代码
2.7.1. 通过MapperMethod执行sql


  • MapperMethod
  1. public class MapperMethod {  private final SqlCommand command;  private final MethodSignature method;  public MapperMethod(Class mapperInterface, Method method, Configuration config) {    //封装sql语句    this.command = new SqlCommand(config, mapperInterface, method);    //封装sql语句的参数    this.method = new MethodSignature(config, mapperInterface, method);  }      public Object execute(SqlSession sqlSession, Object[] args) {    Object result;    //根据sql语句的类型调用CRUD    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);        //返回ma        } else if (method.returnsMap()) {          result = executeForMap(sqlSession, args);        //返回游标--分页?        } else if (method.returnsCursor()) {          result = executeForCursor(sqlSession, args);        //返回一个        } else {          Object param = method.convertArgsToSqlCommandParam(args);          //调用SqlSession的selectOne          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.7.2. 怎么执行sql的


  • DefaultSqlSession
  1.   @Override  public  T selectOne(String statement, Object parameter) {    // Popular vote was to return null on 0 results and throw exception on too many.    //都是调用的list方法    List 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());    //一个都没有返回null    } else {      return null;    }  }    @Override  public  List selectList(String statement, Object parameter) {    return this.selectList(statement, parameter, RowBounds.DEFAULT);  }    @Override  public  List selectList(String statement, Object parameter, RowBounds rowBounds) {    try {          //调用Configuration把sql和参数封装成MapperStatement      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();    }  }
复制代码
2.7.2.1. 把sql语句封装成MappedStatement


  • Configuration
  1. public MappedStatement getMappedStatement(String id) {    return this.getMappedStatement(id, true);  }  public MappedStatement getMappedStatement(String id, boolean validateIncompleteStatements) {    //没有生成过这条语句则重新构建在放入map    if (validateIncompleteStatements) {      buildAllStatements();    }    //从map中取出这条语句,防止反复解析    return mappedStatements.get(id);  }
复制代码
2.7.2.2. 通过Executor执行sql

2.7.2.2.1. 二级缓存中有则直接返回


  • CachingExecutor
  1.   @Override  public  List 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  List 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 list = (List) tcm.getObject(cache, key);        //取出的为空        if (list == null) {          //重新执行sql,再次放入缓存          list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);          tcm.putObject(cache, key, list); // issue #578 and #116        }        return list;      }    }    //BaseExecutor的query方法    return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);  }
复制代码
2.7.2.2.2. 一级缓存中有则直接返回,没有在查数据库


  • BaseExecutor
  1. @SuppressWarnings("unchecked")  @Override  public  List 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 list;    try {      queryStack++;      //一级缓存?      list = resultHandler == null ? (List) 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  List queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {    List list;    localCache.putObject(key, EXECUTION_PLACEHOLDER);    try {    //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;  }
复制代码
2.7.2.2.3. 真正的jdbc操作


  • SimpleExecutor
  1. @Override  public  List 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);     //JDBC操作      stmt = prepareStatement(handler, ms.getStatementLog());      return handler.query(stmt, resultHandler);    } finally {      closeStatement(stmt);    }  }
复制代码
3. 参考


  • mybatis – MyBatis 3 | Introduction

来源:豆瓜网用户自行投稿发布,如果侵权,请联系站长删除

相关推荐

您需要登录后才可以回帖 登录 | 立即注册