devbox
盐析白兔
这个屌丝很懒,什么也没留下!
热门文章
  • 1vue el-tree添加层级指示线_el-tree加虚线
  • 2【科研必备】常用数学符号大全_论文常用符号
  • 3带你认识无线组网中的胖瘦AP以及组网场景,了解企业AP部署_ap胖瘦模式是什么意思
  • 4HTML5.js与@media screen and(){}.js媒体查询技术_"
    当前位置:   article > 正文

    Mybatis源码学习(四)_mybatis sqlexecute

    mybatis sqlexecute

    Mybatis源码分析(四)

    上回我们分析了Mybatis解析mapper映射文件的代码,我们继续上次的分析,开始mybatis执行sql语句的流程,话不多说咱们上代码!!!!!!

    上回总结

    ​ 上回我们分析了mybatis解析mapper映射文件的过程

    1. 解析***Mapper.xml文件的mapper标签;
    2. 解析select|insert|update|delete标签;
    3. 解析动态sql语句将sql语句解析后封装为一个SqlSource
    4. 通过builderAssistant(构建者助手),构建MappedStatement对象;
    5. MappedStatement对象放入configuration对象中的mappedStatementsmap中;

    最终我们的到SqlSessionFactory对象,封装后具体结构如下:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-evWs40J0-1605862861728)(C:\Users\李昊\AppData\Roaming\Typora\typora-user-images\image-20201118205559442.png)]

    开始执行流程
    创建SqlSession对象
    1. 回到我们的main方法中,得到SqlSessionFactory对象后,调用sqlSessionFactory.openSession()方法创建SqlSession对象;

      //通过工厂生产一个sqlsession对象
      SqlSession sqlSession = sqlSessionFactory.openSession();
      
      //调用sqlSessionFactory的openSession方法
       @Override
      public SqlSession openSession() {
         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);
            // 获取JdbcTransaction或者ManagedTransaction
            tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
            // 创建Executor执行器
            final Executor executor = configuration.newExecutor(tx, execType);
            // 创建DefaultSqlSession
            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();
          }
        }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29

      获取事务工厂创建TransactionFactory我们使用的是jdbc,所以创建的是JdbcTransactionFactory,使用JDBC的事务管理机制,就是利用java.sql.Connection对象完成对事务的提交),通过工厂创建Transaction(我们使用的是jdbc,所以创建的是JdbcTransaction);创建Executor执行器,用来操作数据库;

      //Executor执行器
      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);
      		}
      		// 如果开启缓存(默认是开启的),则使用缓存执行器
      		if (cacheEnabled) {
      			executor = new CachingExecutor(executor);
      		}
      		// 插件执行
      		executor = (Executor) interceptorChain.pluginAll(executor);
      		return executor;
      	}
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23

      我们这里创建了一个简单执行器,mybatis默认是开启了一级缓存的,又创建缓存执行器,后面用来执行我们解析好的sql语句,最后创建了一个DefaultSqlSession对象;

    2. 通过SqlSession获取接口的代理对象

          //通过SqlSession获取一个PersionMapper接口的代理对象
          PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
      
          //调用Sqlsession的getMapper调用configuration中的getMapper方法
          public <T> T getMapper(Class<T> type) {
              // 从Configuration对象中,根据Mapper接口,获取Mapper代理对象
              return configuration.<T>getMapper(type, this);
          }
      	//从configuration中取到之前封装好的mapperRegistry
      	//里面有之前放进去的代理对象工厂
      	public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
      		return mapperRegistry.getMapper(type, sqlSession);
      	}
      	//调用mapperRegistry的getMapper方法取到Mapper代理对象工厂
      	//key为接口的class对象,value为接口的代理对象工厂
      	public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
              // 根据Mapper接口的类型,从Map集合中获取Mapper代理对象工厂
              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生产MapperProxy,通过MapperProxy产生Mapper代理对象
                return mapperProxyFactory.newInstance(sqlSession);
              } catch (Exception e) {
                throw new BindingException("Error getting mapper instance. Cause: " + e, e);
              }
        	}
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29

      mapperRegistry中取到mapper的代理对象工厂,并生产MapperProxy,通过MapperProxy产生Mapper代理对象;

    创建Mapper代理对象
    		// 通过MapperProxyFactory生产MapperProxy,通过MapperProxy产生Mapper代理对象
            return mapperProxyFactory.newInstance(sqlSession);
    		
    		//调用生产出来的mapperProxyFactory的newInstance方法,生产mapperProxy
    		public T newInstance(SqlSession sqlSession) {
    			// 创建基于JDK实现的Mapper代理对象
        		final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
        		return newInstance(mapperProxy);
      		}
    		//通过mapperProxy创建Mapper接口代理对象
    		protected T newInstance(MapperProxy<T> mapperProxy) {
    			// 使用JDK动态代理方式,生成代理对象
        		return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
      		}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    这里通过MapperProxyFactory生产了一个MapperProxy对象,通过MapperProxy给予JDK的动态代理创建了一个mapper代理对象;

    1. 执行代理对象的seleceById方法

      		//创建入参对象并赋值
      		Person person1 = new Person();
              person1.setId("1");
              //执行selectById方法传入入参 "1"
              Person person = mapper.selectById(person1);
      		
      		//
      		public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                  try {
                    // 是Interface接口还是Object类
                    // 如果方法是Object类自带的方法,比如没有被重写的 equals toString, hashcode 等,还是执行原来的方法
          		  // getDeclaringClass()返回表示声明由此 Method 对象表示的方法的类或接口的 Class 对象。
                    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);
                  }
                  // 如果不是object的自带方法,先去  Map<Method, MapperMethod> methodCache中找是否已经存在这个method了
                  // 没有就将method封装成MapperMethod存进mehtodCache中然后返回MapperMethod
                  final MapperMethod mapperMethod = cachedMapperMethod(method);
                  // 然后执行MapprMehtod的execute方法(执行sqlsession的方法)
                  return mapperMethod.execute(sqlSession, args);
              }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26

      执行代理对象的seleceById方法,会进入MapperProxy.invoke()方法,判断当前是Interface接口还是Object类,判断有没有缓存这个方法,最后执行MapperProxy.execute()方法;

    2. 执行MapperProxy.execute()方法

      //执行MapperProxy.execute()执行SQL脚本,得到结果对象,然后转换成对应method返回类型的对象
      public Object execute(SqlSession sqlSession, Object[] args) {
          Object result;
          //判断Sql指令类型
          switch (command.getType()) {
            //插入指令
            case INSERT: {
              //构建sql脚本参数名-参数对象映射集合;
          	Object param = method.convertArgsToSqlCommandParam(args);
              //执行插入Sql脚本,然后将更新记录数转换成method所需要的返回类型对象
              result = rowCountResult(sqlSession.insert(command.getName(), param));
              break;
            }
            //修改指令
            case UPDATE: {
              //构建sql脚本参数名-参数对象映射集合;
              Object param = method.convertArgsToSqlCommandParam(args);
              //执行修改Sql脚本,然后将更新记录数转换成method所需要的返回类型对象
              result = rowCountResult(sqlSession.update(command.getName(), param));
              break;
            }
            //删除指令
            case DELETE: {
              //构建sql脚本参数名-参数对象映射集合;
              Object param = method.convertArgsToSqlCommandParam(args);
              result = rowCountResult(sqlSession.delete(command.getName(), param));
              break;
            }
            //查询指令
            case SELECT:
              //如果method返回类型为void 而且 method有ResultHandler类型参数
              if (method.returnsVoid() && method.hasResultHandler()) {
                //用ResultHandler执行查询sql
                executeWithResultHandler(sqlSession, args);
                //处理结果赋值为ull
                result = null;
                //如果method返回类型为Collection的子类或者返回类型是数组
              } else if (method.returnsMany()) {
                /**
                 * 执行查询SQL,默认返回结果对象集合,但如果method返回类型为数组,该方法就会自动将结果对象集合
                 * 转换成数组;如果method返回类型为自定义的Collection实现类,该方法也会将结果对象集合的元素添加到
                 * 自定义的Collection实现类对象中
                 */
                result = executeForMany(sqlSession, args);
                //如果method的返回类型是Map
              } else if (method.returnsMap()) {
                //执行查询SQL,返回结果对象映射赋值给result
                result = executeForMap(sqlSession, args);
                //如果method返回类型是Cursor游标
              } else if (method.returnsCursor()) {
                //执行查询SQL,返回结果对象游标赋值给result
                result = executeForCursor(sqlSession, args);
              } else {
                //构建sql脚本参数名-参数对象映射集合
                Object param = method.convertArgsToSqlCommandParam(args);
                //执行查询SQL,返回结果对象赋值给result
                result = sqlSession.selectOne(command.getName(), param);
                //如果method返回类型为Optional 且 结果对象为null 或者 method返回类型不等于结果对象类型
                if (method.returnsOptional() &&
                    (result == null || !method.getReturnType().equals(result.getClass()))) {
                  //如果对象即可能是 null 也可能是非 null,使用 ofNullable() 方法可以防止空指针异常
                  result = Optional.ofNullable(result);
                }
              }
              break;
            //刷新指令
            case FLUSH:
              //执行全部等待批处理语句,并将结果封装到BatchResult集合中,然后赋值reuslt
              result = sqlSession.flushStatements();
              break;
            default:
              throw new BindingException("Unknown execution method for: " + command.getName());
          }
          //如果结果对象为null 且 method的返回类型为原始类型 且 method的返回类型不是void
          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;
        }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
      • 70
      • 71
      • 72
      • 73
      • 74
      • 75
      • 76
      • 77
      • 78
      • 79
      • 80
    3. 执行SqlSession.selectOne()方法

      		//执行查询SQL,返回结果对象赋值给result
              result = sqlSession.selectOne(command.getName(), param);
      
      		//执行SqlSession的selectOne方法
      		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;
                  }
      		}
      		
      		//执行SqlSession的selectList
      		public <E> List<E> selectList(String statement, Object parameter) {
      			return this.selectList(statement, parameter, RowBounds.DEFAULT);
      		}
      
      		//执行selectList方法
      		public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
                  try {
                      // 根据传入的statementId,获取MappedStatement对象
                      MappedStatement ms = configuration.getMappedStatement(statement);
                      // 调用执行器的查询方法
                      // RowBounds是用来逻辑分页(按照条件将数据从数据库查询到内存中,在内存中进行分页)
                      // wrapCollection(parameter)是用来装饰集合或者数组参数
                      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();
                  }
      		}
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37

      根据statementId在configuration中取到对应的MappedStatement对象,调用执行器执行查询方法;

    调用执行器的查询方法(获取boundSql
    	//调用之前创建的CachingExecutor的query方法
      public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) 			throws SQLException {
    	// 获取绑定的SQL语句,比如“SELECT * FROM user WHERE id = ? ”
        BoundSql boundSql = ms.getBoundSql(parameterObject);
        // 生成缓存Key
        CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
    
        return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
      }
    
    	//调用MappedStatement.getBoundSql()获取绑定的SQL语句
    	public BoundSql getBoundSql(Object parameterObject) {
            // 调用SqlSource获取BoundSql
            BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
            List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
            if (parameterMappings == null || parameterMappings.isEmpty()) {
              boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);
            }
    
            // check for nested result maps in parameter mappings (issue #30)
            for (ParameterMapping pm : boundSql.getParameterMappings()) {
              String rmId = pm.getResultMapId();
              if (rmId != null) {
                ResultMap rm = configuration.getResultMap(rmId);
                if (rm != null) {
                  hasNestedResultMaps |= rm.hasNestedResultMaps();
                }
              }
            }
            return boundSql;
      	}
    
    	//调用SqlSource获取BoundSql
    	public BoundSql getBoundSql(Object parameterObject) {
            //创建动态sql上下文
    		DynamicContext context = new DynamicContext(configuration, parameterObject);
    		// 此处会调用MixedSqlNode中包含的所有SqlNode的apply方法
    		// 此处会处理${},也会处理动态标签
    		// 最终将所有的SqlNode信息进行解析之后,追加到DynamicContext对象的StringBuilder对象中
    		rootSqlNode.apply(context);
    		// 创建SQL信息解析器
    		SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
    		// 获取入参类型
    		Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
    		// 执行解析:将带有#{}的SQL语句进行解析,然后封装到StaticSqlSource中
    		SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
    		// 将解析后的SQL语句还有入参绑定到一起(封装到一个对象中,此时还没有将参数替换到SQL占位符?)
    		BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
    		for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) {
    			boundSql.setAdditionalParameter(entry.getKey(), entry.getValue());
    		}
    		return boundSql;
    	}
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    创建动态SQL上下文,执行SqlSource中封装的rootSqlNode的apply方法,处理${}、处理动态标签,将处理过后的sql追加到动态SQL上下文中的StringBuilder对象中;

    这里详细讲解一下每个SqlNode

    SQLNode:每个Xml Node都会解析成对应的SQLNode对象

    image-20201119223054796

    //SqlNode接口
    public interface SqlNode {
    	//将各个Sql片段合并到DynamicContext中,拼接为完整的SQL;
      boolean apply(DynamicContext context);
    }
    
    //MixedSqlNode
    public class MixedSqlNode implements SqlNode {
    //记录sql节点中的所有SQL片段
     private final List<SqlNode> contents;
    
     public MixedSqlNode(List<SqlNode> contents) {
        this.contents = contents;
     }
      @Override
      public boolean apply(DynamicContext context) {
        for (SqlNode sqlNode : contents) {
          sqlNode.apply(context);
        }
        return true;
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    通过解析Sql节点得到的MixedSqlNode结构如下:

    20190521234639777

    1. StaticSqlSource:最简单的SqlNode,功能仅仅是将自身记录的text拼接到context上下文中;

      //StaticTextSqlNode
      public class StaticTextSqlNode implements SqlNode {
        private final String text;
      
        public StaticTextSqlNode(String text) {
          this.text = text;
        }
      
        @Override
        public boolean apply(DynamicContext context) {
          context.appendSql(text);
          return true;
        }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
    2. TextSqlNode:表示包含‘${}’占位符的动态Sql节点;

      	//使用GenericTokenParser解析‘${}’,并直接转换成传入的实际参数
      	public boolean apply(DynamicContext context) {
      		GenericTokenParser parser = createParser(new BindingTokenParser(context, injectionFilter));
      		context.appendSql(parser.parse(text));
      		return true;
      	}
      	//实际参数值获取逻辑方法
      	
      	@Override
      	public String handleToken(String content) {
              // 获取入参对象
              Object parameter = context.getBindings().get("_parameter");
              // 如果入参对象为null或者入参对象是简单类型,不需要关注${}中的名称,直接设置${}的参数名称必须为value
              // 如果content不为value,则取不出数据,会报错
              if (parameter == null) {
                  // context.getBindings().put("value", null);
                  return "";
              } else if (SimpleTypeRegistry.isSimpleType(parameter.getClass())) {
                  // context.getBindings().put("value", parameter);
                  return String.valueOf(parameter);
              }
              // 使用Ognl API,通过content中的表达式去获取入参对象中的指定属性值
              // context.getBindings()就是一个ContextMap对象,也是HashMap的子对象
              Object value = OgnlCache.getValue(content, parameter);
              String srtValue = value == null ? "" : String.valueOf(value); // issue #274 return "" instead of "null"
              checkInjection(srtValue);
              return srtValue;
      	}
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
    3. IFSqlNode:if标签平常使用的是最多的,在处理对应的逻辑节点时,主要工作就是通过Ognl表达式和传入的参数进行判断,看传入的参数是否满足if test里的表达式,满足将SQL片段合并到context上下文中。若不满足test则过滤掉这一部分的SQL片段,不添加到context中;

      @Override
      public boolean apply(DynamicContext context) {
          //通过Ognl表达式和传入的参数进行判断,看传入的参数是否满足if test里的表达式
        if (evaluator.evaluateBoolean(test, context.getBindings())) {
          contents.apply(context);
          return true;
        }
        return false;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
    4. WhereSqlNodeSetSqlNode:都是继承自TrimSqlNode

      1. WhereSqlNode:会传入prefix=WHEREprefixesToOverride=["AND ","OR ","AND\n", "OR\n", "AND\r", "OR\r", "AND\t", "OR\t"];
      2. SetSqlNode:会传入prefix=WHEREprefixesToOverride=[“,”];
      3. 会传入prefix=WHEREprefixesToOverride=[“,”];
    5. TrimSqlNode:<trim /> 标签的SqlNode实现类;

    6. ForEachSqlNode:<foreach /> 标签的SqlNode实现类;

    7. VarDeclSqlNode: <bind /> 标签的SqlNode实现类;

    最后动态sql上下文中拼接好的sql为:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8BoYMI8n-1605862861730)(C:\Users\李昊\AppData\Roaming\Typora\typora-user-images\image-20201119230954378.png)]

    1. 解析’#{}’

      //创建SqlSourceBuilder解析#{}
      public SqlSource parse(String originalSql, Class<?> parameterType, Map<String, Object> additionalParameters) {
         ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(configuration, parameterType,
               additionalParameters);
         // 创建分词解析器
         GenericTokenParser parser = new GenericTokenParser("#{", "}", handler);
         // 解析#{}
         String sql = parser.parse(originalSql);
         // 将解析之后的SQL信息,封装到StaticSqlSource对象中
         // SQL字符串是带有?号的字符串,?相关的参数信息,封装到ParameterMapping集合中
         return new StaticSqlSource(configuration, sql, handler.getParameterMappings());
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
    2. 调用缓存执行器的query方法;

      @Override
       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) {
               // 委托给BaseExecutor执行
               list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
               tcm.putObject(cache, key, list); // issue #578 and #116
             }
             return list;
           }
         }
         // 委托给BaseExecutor执行
         return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
       }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25

      这里查看是否存在二级缓存,如果存在则查询二级缓存,不存在则查询数据库(前提是开启了mybatis的二级缓存)

    3. 委托给BaseExecutor执行查询方法

      @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++;
          // 从一级缓存中获取数据
          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;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36

      查看一级缓存是否有数据,没有的话则从数据库查询;

    4. 调用BaseExecutor.queryFromDatabase()方法

      //调用BaseExecutor.queryFromDatabase()方法
      private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
          List<E> list;
          //将缓存key存入一级缓存中
          localCache.putObject(key, EXECUTION_PLACEHOLDER);
          try {
            // 执行查询
            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;
        }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18

      将处理好的sql,以及查询结果存入一级缓存中,执行查询方法;

    5. 执行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 configuration = ms.getConfiguration();
      			// 创建RoutingStatementHandler,用来处理Statement
      			// RoutingStatementHandler类中初始化delegate类(SimpleStatementHandler、PreparedStatementHandler)
      			StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds,
      					resultHandler, boundSql);
      			// 子流程1:设置参数
      			stmt = prepareStatement(handler, ms.getStatementLog());
      			// 子流程2:执行SQL语句(已经设置过参数),并且映射结果集
      			return handler.query(stmt, resultHandler);
      		} finally {
      			closeStatement(stmt);
      		}
      	}
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
    创建Statement处理器

    创建RoutingStatementHandler用来处理对应的Statement,构造方法如下;

    //根据不同的类型创建不同的Statement处理器,进行处理
    public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    
        switch (ms.getStatementType()) {
          //简单的Statement处理器
          case STATEMENT:
            delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
            break;
          //PreparedStatement处理器
          case PREPARED:
            delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
            break;
          //callable处理器
          case CALLABLE:
            delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
            break;
          default:
            throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
        }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    根据不同的类型创建不同的Statement处理器,处理statement;

    1. 设置参数,执行Statement处理器的prepareStatement方法
    //后获取jdbc链接,创建Statement并设置Statement参数
    private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    		Statement stmt;
    		// 获取连接
    		Connection connection = getConnection(statementLog);
    		// 创建Statement(PreparedStatement、Statement、CallableStatement)
    		stmt = handler.prepare(connection, transaction.getTimeout());
    		// SQL参数设置
    		handler.parameterize(stmt);
    		return stmt;
    	}
    
    //创建prepareStatement
    public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
        ErrorContext.instance().sql(boundSql.getSql());
        Statement statement = null;
        try {
          // 实例化Statement,比如PreparedStatement
          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);
        }
      }
    
    //创建prepareStatement
    protected Statement instantiateStatement(Connection connection) throws SQLException {
    	// 获取带有占位符的SQL语句
        String sql = boundSql.getSql();
        // 处理带有主键返回的SQL
        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);
        }
      }
    
    //调用prepareStatement的parameterize方法,使用parameterHandler参数处理器设置参数
    public void parameterize(Statement statement) throws SQLException {
    	// 通过ParameterHandler处理参数
        parameterHandler.setParameters((PreparedStatement) statement);
      }
    
    //对prepareStatement设置参数
    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 jdbcType = parameterMapping.getJdbcType();
    					if (value == null && jdbcType == null) {
    						jdbcType = configuration.getJdbcTypeForNull();
    					}
    					try {
    						// 给PreparedStatement设置参数
    						typeHandler.setParameter(ps, i + 1, value, jdbcType);
    					} catch (TypeException e) {
    						throw new TypeException(
    								"Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
    					} catch (SQLException e) {
    						throw new TypeException(
    								"Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
    					}
    				}
    			}
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101

    在参数处理器中创建每个参数的typeHandler(类型处理器的)setParameter方法,设置参数;

    1. 执行StatementHandler的query方法执行sql语句

      //执行PreparedStatement,也就是执行SQL语句
      public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
          PreparedStatement ps = (PreparedStatement) statement;
          // 执行PreparedStatement,也就是执行SQL语句
          ps.execute();
          // 处理结果集
          return resultSetHandler.handleResultSets(ps);
        }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
    2. 处理结果集

      public List<Object> handleResultSets(Statement stmt) throws SQLException {
      		ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
      
      		// <select>标签的resultMap属性,可以指定多个值,多个值之间用逗号(,)分割
      		final List<Object> multipleResults = new ArrayList<>();
      
      		int resultSetCount = 0;
      		// 这里是获取第一个结果集,将传统JDBC的ResultSet包装成一个包含结果列元信息的ResultSetWrapper对象
      		ResultSetWrapper rsw = getFirstResultSet(stmt);
      
      		// 这里是获取所有要映射的ResultMap(按照逗号分割出来的)
      		List<ResultMap> resultMaps = mappedStatement.getResultMaps();
      		// 要映射的ResultMap的数量
      		int resultMapCount = resultMaps.size();
      		validateResultMapsCount(rsw, resultMapCount);
      		// 循环处理每个ResultMap,从第一个开始处理
      		while (rsw != null && resultMapCount > resultSetCount) {
      			// 得到结果映射信息
      			ResultMap resultMap = resultMaps.get(resultSetCount);
      			// 处理结果集
      			// 从rsw结果集参数中获取查询结果,再根据resultMap映射信息,将查询结果映射到multipleResults中
      			handleResultSet(rsw, resultMap, multipleResults, null);
      
      			rsw = getNextResultSet(stmt);
      			cleanUpAfterHandlingResultSet();
      			resultSetCount++;
      		}
      
      		// 对应<select>标签的resultSets属性,一般不使用该属性
      		String[] resultSets = mappedStatement.getResultSets();
      		if (resultSets != null) {
      			while (rsw != null && resultSetCount < resultSets.length) {
      				ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
      				if (parentMapping != null) {
      					String nestedResultMapId = parentMapping.getNestedResultMapId();
      					ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
      					handleResultSet(rsw, resultMap, null, parentMapping);
      				}
      				rsw = getNextResultSet(stmt);
      				cleanUpAfterHandlingResultSet();
      				resultSetCount++;
      			}
      		}
      
      		// 如果只有一个结果集合,则直接从多结果集中取出第一个
              return collapseSingleResultList(multipleResults);
      	}
      
      //调用上边的handleResultSet(rsw, resultMap, multipleResults, null);
      //处理结果映射
      private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults,
      			ResultMapping parentMapping) throws SQLException {
      		try {
      			// 处理嵌套结果映射
      			if (parentMapping != null) {
      				handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
      			} else {
      				// 第一次一般来说resultHandler为空,则创建DefaultResultHandler来处理结果
      				if (resultHandler == null) {
      					DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
      					// 处理行数据,其实就是完成结果映射
      					handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
      
      					multipleResults.add(defaultResultHandler.getResultList());
      				} else {
      					handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
      				}
      			}
      		} finally {
      			// issue #228 (close resultsets)
      			closeResultSet(rsw.getResultSet());
      		}
      	}
      
      //判断映射嵌套关系
      public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler,
      			RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
      		// 是否有内置嵌套的结果映射
      		if (resultMap.hasNestedResultMaps()) {
      			ensureNoRowBounds();
      			checkResultHandler();
      			// 嵌套结果映射
      			handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
      		} else {
      			// 简单结果映射
      			handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
      		}
      }
      
      //处理简单的映射关系
      private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap,
      			ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
      		DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
      		// 获取结果集信息
      		ResultSet resultSet = rsw.getResultSet();
      		// 使用rowBounds的分页信息,进行逻辑分页(也就是在内存中分页)
      		skipRows(resultSet, rowBounds);
      		while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
      			// 通过<resultMap>标签的子标签<discriminator>对结果映射进行鉴别
      			ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
      			// 将查询结果封装到POJO中
      			Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
      			// 处理对象嵌套的映射关系
      			storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
      		}
      }
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
      • 70
      • 71
      • 72
      • 73
      • 74
      • 75
      • 76
      • 77
      • 78
      • 79
      • 80
      • 81
      • 82
      • 83
      • 84
      • 85
      • 86
      • 87
      • 88
      • 89
      • 90
      • 91
      • 92
      • 93
      • 94
      • 95
      • 96
      • 97
      • 98
      • 99
      • 100
      • 101
      • 102
      • 103
      • 104
      • 105
      • 106
      • 107

      处理完成后,将查询到的结果返回;

      到这里我们完整的走了一遍Mybatis通过接口Mapper映射文件查询数据库,经过了解析xml、封装SQl、获取SQl、执行SQl、解析结果集。希望通过学习源码让自己对框架的了解更深一些.

    声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/346954
    推荐阅读
    相关标签