上节分析了Mapper对象的创建。
在ORM的定义中可以理解为Object->SQLMapper抽象层(这一层并不负责具体的SQL执行。这一层可以理解为SQL代理层)
本节分析以下内容:
①SqlSession在具体执行SQL时,如果通过namespace+sqlid定位到具体的MappedStatement(sql的对象化表现形式)
②参数(Object) 如何填充到具体的SQL
③SQL是如何执行的
- 获取StateMentMapper.前面讲到初始化时,会缓存MappedStatement,MappedStatement被保存在StrictMap中.
StrictMap是Mybatis实现HashMap子类。Key重复放入的时候会报错。
- 参数(Object) 如何填充到具体的SQL(Param-SQL的Orm转换)
1、通过Executor执行SQL
2、Executor是如何获取的?
SqlSessionFactory工厂中代码如下:
从Configuration中获得Excecutor,默认的执行器类型为configuration.getDefaultExecutorType()在configuration类中定义为
protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
ExecutorType.SIMPLE会创建何种执行器?
来看Configuraiton的获得执行器的方法
默认的执行器为:SimpleExecutor,而cacheEnabled默认值为true.所以实际是CachingExecutor,使用了装饰器模式。
- Excecutor是如何将参数成功映射到具体SQL的参数?
先看下MappedStatement中的类成员构成。sqlSource是具体获取待执行SQL的对象。
- sqlSource接口定义:
BoundSql getBoundSql(Object parameterObject)的方法,改方调用实际的SqlSource的实现类,来获取真正执行的SQL
先说说几个处理类的区别:
DynamicSqlSource:sql中包含
看一段代码,我们关注rootSqlNode变量,以及getBoundSql()方法的执行。
<span style="color: #0000ff">private <span style="color: #0000ff">final<span style="color: #000000"> SqlNode rootSqlNode;
<span style="color: #0000ff">public<span style="color: #000000"> DynamicSqlSource(Configuration configuration,SqlNode rootSqlNode) {
<span style="color: #0000ff">this.configuration =<span style="color: #000000"> configuration;
<span style="color: #0000ff">this.rootSqlNode =<span style="color: #000000"> rootSqlNode;
}
@Override
<span style="color: #0000ff">public<span style="color: #000000"> BoundSql getBoundSql(Object parameterObject) {
DynamicContext context = <span style="color: #0000ff">new<span style="color: #000000"> DynamicContext(configuration,parameterObject);
rootSqlNode.apply(context);
SqlSourceBuilder sqlSourceParser = <span style="color: #0000ff">new<span style="color: #000000"> SqlSourceBuilder(configuration);
Class<?> parameterType = parameterObject == <span style="color: #0000ff">null ? Object.<span style="color: #0000ff">class<span style="color: #000000"> : parameterObject.getClass();
SqlSource sqlSource =<span style="color: #000000"> sqlSourceParser.parse(context.getSql(),parameterType,context.getBindings());
BoundSql boundSql =<span style="color: #000000"> sqlSource.getBoundSql(parameterObject);
<span style="color: #0000ff">for (Map.Entry<String,Object><span style="color: #000000"> entry : context.getBindings().entrySet()) {
boundSql.setAdditionalParameter(entry.getKey(),entry.getValue());
}
<span style="color: #0000ff">return<span style="color: #000000"> boundSql;
}
解析过程描述:
①rootSqlNode为从XML解析的具体SQL节点,每一行作为一个node。对于
②
看一段IfSqlNode的代码:apply方法中的evaluateBoolean方法,将对
<span style="color: #0000ff">this.test =<span style="color: #000000"> test;
<span style="color: #0000ff">this.contents =<span style="color: #000000"> contents;
<span style="color: #0000ff">this.evaluator = <span style="color: #0000ff">new<span style="color: #000000"> ExpressionEvaluator();
}
@Override
<span style="color: #0000ff">if<span style="color: #000000"> (evaluator.evaluateBoolean(test,context.getBindings())) {
contents.apply(context);
<span style="color: #0000ff">return <span style="color: #0000ff">true<span style="color: #000000">;
}
<span style="color: #0000ff">return <span style="color: #0000ff">false<span style="color: #000000">;
}
}
mybatis中定义的SQL节点如下。
RawSqlSource:对于不包含
DynamicSqlSource: 对sql中包含${}参数的会转换为该对象
- SqlSource的转换是在初始化加载时完成。那真正的参数是何时转换为SQL?
SimpleExecutor中,创建PrepareStateMent的过程。
离我们想知道的真相越来越近了,来看具体的参数化过程
StateMentHandler.parameterize
RoutingStatementHandler用来做路由器:根据实际的StatementType做路由
我们来看PreparedStatementHadler
</span><span style="color: #0000ff">try</span><span style="color: #000000"> {
<strong>typeHandler</strong>.setParameter(ps,i </span>+ 1<span style="color: #000000">,value,jdbcType);
} </span><span style="color: #0000ff">catch</span><span style="color: #000000"> (TypeException var10) {
</span><span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span> TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " +<span style="color: #000000"> var10,var10);
} </span><span style="color: #0000ff">catch</span><span style="color: #000000"> (SQLException var11) {
</span><span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span> TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " +<span style="color: #000000"> var11,var11);
}
}
}
}
}</span></em></em></em></em></em></em></em></em></pre>
TypeHandler的继承关系如下:
我们查看其中的BigDecimalTypeHandler的源码
<span style="color: #0000ff">public
<span style="color: #0000ff">throws<span style="color: #000000"> SQLException {
ps.setBigDecimal(i,parameter);
}
@Override
<span style="color: #0000ff">public<span style="color: #000000"> BigDecimal getNullableResult(ResultSet rs,String columnName)
<span style="color: #0000ff">throws<span style="color: #000000"> SQLException {
<span style="color: #0000ff">return<span style="color: #000000"> rs.getBigDecimal(columnName);
}
@Override
<span style="color: #0000ff">public BigDecimal getNullableResult(ResultSet rs,<span style="color: #0000ff">int<span style="color: #000000"> columnIndex)
<span style="color: #0000ff">throws<span style="color: #000000"> SQLException {
<span style="color: #0000ff">return<span style="color: #000000"> rs.getBigDecimal(columnIndex);
}
@Override
<span style="color: #0000ff">public BigDecimal getNullableResult(CallableStatement cs,<span style="color: #0000ff">int<span style="color: #000000"> columnIndex)
<span style="color: #0000ff">throws<span style="color: #000000"> SQLException {
<span style="color: #0000ff">return<span style="color: #000000"> cs.getBigDecimal(columnIndex);
}
}
会调用JDBCAPI中的相应方法获得正确的值