StatementHandler的整体结构 PreparedStatementHandler实现自StatementHandler,我们先看下StatementHandler的结构
StatementHandler的执行流程
请求参数处理 所谓的请求参数处理,就是将入参转换为JDBC参数的过程。主要分为两个步骤,一是参数的转换,二是参数的映射。
参数的转换 如果是单个参数,我们的请求参数会被转换为一个Object对象;如果是多个请求参数,或者单个参数但是被加了@Param注解,那么我们的入参是会被转换成Map。举个例子:
1 2 @Select("SELECT * FROM T_USER WHERE id = #{user.id} OR USER_NAME = #{name}") UserPO selectUserWithPo (@Param("user") UserPO userPO, @Param("name") String name) ;
参数转换的源码如下:
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 public Object getNamedParams (Object[] args) { final int paramCount = names.size(); if (args == null || paramCount == 0 ) { return null ; } if (!hasParamAnnotation && paramCount == 1 ) { Object value = args[names.firstKey()]; return wrapToMapIfCollection(value, useActualParamName ? names.get(names.firstKey()) : null ); } else { final Map<String, Object> param = new ParamMap <>(); int i = 0 ; for (Map.Entry<Integer, String> entry : names.entrySet()) { param.put(entry.getValue(), args[entry.getKey()]); final String genericParamName = GENERIC_NAME_PREFIX + (i + 1 ); if (!names.containsValue(genericParamName)) { param.put(genericParamName, args[entry.getKey()]); } i++; } return param; } }
参数的映射处理 Mybatis会为每个参数生成一个ParameterMapping,并收集到List中。然后遍历这个集合,再根据具体的参数和jdbcType获取这个参数对应的TypeHandler,比如IntegerTypeHandler,StringTypeHandler等等,然后通过TypeHandler设置属性值。
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 public void setParameters (PreparedStatement ps) { ErrorContext.instance().activity("setting parameters" ).object(mappedStatement.getParameterMap().getId()); List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); if (parameterMappings != null ) { MetaObject metaObject = 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)) { value = boundSql.getAdditionalParameter(propertyName); } else if (parameterObject == null ) { value = null ; } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { value = parameterObject; } else { if (metaObject == null ) { metaObject = configuration.newMetaObject(parameterObject); } value = metaObject.getValue(propertyName); } TypeHandler typeHandler = parameterMapping.getTypeHandler(); JdbcType jdbcType = parameterMapping.getJdbcType(); if (value == null && jdbcType == null ) { 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); } } } } }
结果集处理 结果集是如何被处理为我们需要的javaBean的呢?也大致分为三块儿内容
简单来说,先遍历resultMap,然后再遍历结果集处理每一行的数据。在处理一行数据的过程中,会获取对象的属性集合,然后遍历属性的集合,获取每个属性对应的TypeHandler,并通过调用这个TypeHandler的getResult()从结果集中获取这个属性对应的值,然后将这个属性放到一个集合中返回,然后通过ObjectFactory将这个属性的集合构造出一个对象返回,最后将这个对象放入到ResultHandler中的集合中,整个流程结束。
来一个简单的时序图(加载比较慢…):
sequenceDiagram
ResultSetHandler->>ResultSetHandler: 获取resultMaps
loop resultMaps
ResultSetHandler->>ResultSetHandler: 设置分页
loop 遍历结果集
loop 遍历对象属性
ResultSetHandler->>ResultSetHandler: 获取TypeHandler
ResultSetHandler->>TypeHandler: 获取属性的值
TypeHandler-->>ResultSetHandler: 返回value
ResultSetHandler->>ResultSetHandler: value放入集合,并返回true
end
ResultSetHandler->>ResultSetHandler: 通过objectFactory生成Object对象
ResultSetHandler->>ResultContext: 将对象放入ResultContext中,累计resultCount
ResultSetHandler->>ResultHandler: 将ResultContext中的数据放入ResultHandler的集合中
end
ResultSetHandler->>ResultSetHandler: 将ResultHandler的集合中数据放入multipleResults
ResultSetHandler->>ResultSetHandler: 关闭ResultSet
end
ResultSetHandler->>ResultSetHandler: 返回multipleResults