--- layout: post title: Mybatis源码分析(1) - Mybatis关键类 category: 技术 tags: Mybatis keywords: description: --- # 参数解析 `ParamNameResolver`类用于解析接口方法中传递的参数 重要方法:`getNamedParams` 解析步骤: 1. 如果没有参数,直接返回null 2. 如果没有并且参数数量为1,则取第一个参数值 3. 在有注解或者参数数量大于1的情况下,将参数转为Map形式,有注解的,map中的key为注解的value值,没有注解的使用参数顺序号,从0开始。且mybatis会自动生成参数名前缀为`param`的参数。 ``` //key -> value 0 -> 123 1 -> 234 param0 -> 123 param1 -> 234 ``` 其中key=0和param0表示的同一个参数,两种key `ParameterMapping` 为每个参数名称,参数类型的处理类。 `ParameterMappingTokenHandler`用于处理解析Sql中的占位符变量 # 方法体 `org.apache.ibatis.mapping.MappedStatement`类用于解析并xml文件中的每个方法标签中的Sql并将其转换为java中的代码格式。 主要结构包括 |参数名|类型|功能|备注| |---|---|---|---| |configuration|Configuration|整个mybatis所有配置信息类|| |id|唯一指定该方法的id,为方法名或全限定方法名||| |statementType|StatementType|Sql语句的类型,`STATEMENT`、`PREPARED`、`CALLABLE`|| |resultSetType|ResultSetType|结果集类型。`FORWARD_ONLY`、`TYPE_SCROLL_INSENSITIVE`、`TYPE_SCROLL_SENSITIVE`|| |sqlSource|SqlSource|内部结构为`BoundSql`|BoundSql包含完整的Sql,含有类型信息的参数以及参数名和参数值的映射表| |parameterMap|ParameterMap|**待补充描述**|| |resultMaps|List|**待补充描述**| |sqlCommandType|SqlCommandType|Sql命令的类型。包括:`INSERT`, `UPDATE`,`DELETE`,`SELECT`,`FLUSH`| |keyGenerator|KeyGenerator|主键生成的类。实现类有:`SelectKeyGenerator`、`Jdbc3KeyGenerator`、`NoKeyGenerator`| |keyProperties|String[]|指定key的属性,该属性为pojo的属性名| |keyColumns|String[]|指定key的列,该属为表中的字段| |statementLog|Log|指定的语句打印的日志类|| |lang|LanguageDriver|生成Sql的驱动器,实现类有:`XMLLanguageDriver`和`RawLanguageDriver`。其中`RawLanguageDriver`是继承的`XMLLanguageDriver`,且不支持胴体Sql| 在`MappedStatement.getBoundSql`通过传入的参数,完成Sql的解析和构建。 # Sql解析 `DynamicContext`为主要的动态Sql的操作类 其中有参数bindings,结构为ContextMap,重写了hashMap的get方法。在实例化`DynamicContext`时会设置`_parameter`和`_databaseId`两个key `SqlSourceBuilder`会通过`parse`方法将原始Sql和绑定的参数进行解析,使用`GenericTokenParser`将初步解析出来的动态sql中的`#{var}`替换为`?`,并将对应的`var`通过`ParameterMappingTokenHandler`设置到`ParameterMapping`中。 Sql到这里已经解析完毕,可以将其转化为你静态Sql了,将解析后的sql赋给`StaticSqlSource`生成新对象 ## 动态Sql的片段 在Mybatis中,初始化时会根据标签,将Sql代码片段解析到对应的SqlNode中,在实际执行时进行解析。 SqlNode集合 |类型|功能|备注| |---|---|---| |MixedSqlNode|整个Sql语句的总的SqlNode|不具有实际的解析能力。是集合该sql下所有sql片段的地方。| |StaticTextSqlNode|存储Sql中静态的文本Sql|只存储不解析| |ForEachSqlNode|对应xml中的`foreach`标签。`ForEachSqlNode`内属性分别对应标签上的各属性。通过内部解析器ExpressionEvaluator将collect中指定的属性的值取出(采用OGNL方式)|| |||| |||| |||| |||| |||| |||| |||| # Session `DefaultSession`为默认实现类 该类中有个比较重要的包装参数的方法:`wrapCollection`。对于Collection类型和数组类型的参数,会给转为Map,且key分别为`list`和`array`。 # 总结 通过整理每个包的主要功能。通览整个mybatis的代码结构,了解各个组件的位置和大概的处理关系。为后续分析源码打下基础。 # 可能的问题 动态Sql每次请求都要重新解析一次,可能每次传入的参数不同,解析也就不同。 StatementHandler每个Session都需要重新建立实例