mybatis关于ORM的使用以及设计(三)[参数对象转换为SQL语言]

上节分析了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

List= ExceptionFactory.wrapException("Error querying database. Cause: " +

 2、Executor是如何获取的?

  SqlSessionFactory工厂中代码如下:

   从Configuration中获得Excecutor,默认的执行器类型为configuration.getDefaultExecutorType()在configuration类中定义为

  protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;

SqlSession openSessionFromDataSource(ExecutorType execType,TransactionIsolationLevel level,= Environment environment = TransactionFactory transactionFactory == Executor executor = ExceptionFactory.wrapException("Error opening session. Cause: " +

  ExecutorType.SIMPLE会创建何种执行器?

  来看Configuraiton的获得执行器的方法

  默认的执行器为:SimpleExecutor,而cacheEnabled默认值为true.所以实际是CachingExecutor,使用了装饰器模式。

= executorType == ?= executorType == ? (ExecutorType.BATCH === BatchExecutor( (ExecutorType.REUSE === ReuseExecutor(executor = SimpleExecutor(,transaction); } cacheEnabled) { executor = CachingExecutor(executor); } executor =
  •   Excecutor是如何将参数成功映射到具体SQL的参数?

   先看下MappedStatement中的类成员构成。sqlSource是具体获取待执行SQL的对象。

      

  •   sqlSource接口定义:
    BoundSql getBoundSql(Object parameterObject)的方法,改方调用实际的SqlSource的实现类,来获取真正执行的SQL

    

  先说说几个处理类的区别:

  DynamicSqlSource:sql中包含等条件是,会被定义为.通过具体的Node处理对象,拼接SQL。

  看一段代码,我们关注rootSqlNode变量,以及getBoundSql()方法的执行。

  

DynamicSqlSource <span style="color: #0000ff">private <span style="color: #0000ff">final<span style="color: #000000"> Configuration configuration;
<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。对于等。每一个节点是一个node

  ②的判断是在具体的node中执行的。SQLNode有以下几种类型。

  

  看一段IfSqlNode的代码:apply方法中的evaluateBoolean方法,将对语句进行判断,返回结果。如果结果为真,则把条件添加到contents 

IfSqlNode <span style="color: #0000ff">public<span style="color: #000000"> IfSqlNode(SqlNode contents,String test) {
<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">public <span style="color: #0000ff">boolean<span style="color: #000000"> apply(DynamicContext context) {
<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:对于不包含等条件判断,替换#{}变为? 在创建RawSqlSource对象时执行这项操作

  DynamicSqlSource: 对sql中包含${}参数的会转换为该对象

  •   SqlSource的转换是在初始化加载时完成。那真正的参数是何时转换为SQL?

  SimpleExecutor中,创建PrepareStateMent的过程。

  

List doQuery(MappedStatement ms,RowBounds rowBounds,ResultHandler resultHandler,BoundSql boundSql) = = StatementHandler handler = configuration.newStatementHandler(wrapper,ms,parameter,resultHandler,boundSql); stmt = handler.
Statement prepareStatement(StatementHandler handler,Log statementLog) == handler.prepare(connection,transaction.getTimeout());  //设置参数 handler.parameterize(stmt);

  离我们想知道的真相越来越近了,来看具体的参数化过程

  StateMentHandler.parameterize

  RoutingStatementHandler用来做路由器:根据实际的StatementType做路由

  我们来看PreparedStatementHadler

parameterize(Statement statement)

  

 List parameterMappings = this.boundSql.getParameterMappings();          if (parameterMappings != null) {        String propertyName = (= (.parameterObject == =  //如果有typeHandler则用TypeHandler处理参数            //一些基础类型是有typeHandler的 } (.typeHandlerRegistry.hasTypeHandler(=  //如果没有typeHandler,通过反射,获得Bean参数中的值 MetaObject metaObject = .configuration.newMetaObject(=//根据参数的JDBCtype找到TypeHandler,设置到PrePareStatement中 TypeHandler typeHandler == (value == && jdbcType == = </span><span style="color: #0000ff"&gt;try</span><span style="color: #000000"&gt; { <strong>typeHandler</strong>.setParameter(ps,i </span>+ 1<span style="color: #000000"&gt;,value,jdbcType); } </span><span style="color: #0000ff"&gt;catch</span><span style="color: #000000"&gt; (TypeException var10) { </span><span style="color: #0000ff"&gt;throw</span> <span style="color: #0000ff"&gt;new</span> TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " +<span style="color: #000000"&gt; var10,var10); } </span><span style="color: #0000ff"&gt;catch</span><span style="color: #000000"&gt; (SQLException var11) { </span><span style="color: #0000ff"&gt;throw</span> <span style="color: #0000ff"&gt;new</span> TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " +<span style="color: #000000"&gt; var11,var11); } } } } }</span></em></em></em></em></em></em></em></em></pre>

  TypeHandler的继承关系如下:

  

   

  我们查看其中的BigDecimalTypeHandler的源码

  

BigDecimalTypeHandler BaseTypeHandler@Override
<span style="color: #0000ff">public
<span style="color: #0000ff">void
setNonNullParameter(PreparedStatement ps,<span style="color: #0000ff">int
<span style="color: #000000"> i,BigDecimal parameter,JdbcType jdbcType)
<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中的相应方法获得正确的值

  

相关文章

1.pom.xml引入依赖 &lt;dependency&gt; &lt;gro...
&lt;?xml version=&quot;1.0&quot; encoding=&a...
准备工作 ① 创建数据库&amp;数据表 ## 创建数据库 CREA...
MyBatis逆向工程是指根据数据库表结构自动生成对应的实体类、...
MyBatis获取参数值的两种方式:${}和#{} ${}的本质就是字符串...
resultMap作用是处理数据表中字段与java实体类中属性的映射关...