Mybatis执行过程简介

以下是使用mybatis默认设置PreparedStatement执行insert的简略时序图,省略了XMLConfigBuilder.parse()的解析细节,缓存和事务等的使用,可以和源码对照着看

XMLConfigBuilder:解析mybatis配置文件

  XMLMapperBuilder: 解析mapper配置文件

    XMLStatementBuilder: 解析SQL语句标签(此处得到SqlSource对象)

注意:

  1. KeyGenerator的设置也是在XMLConfigBuilder.parse()过程中进行的,每个mapper文件中的每个不同id的标签(insert | update等),可能对应的KeyGeneratior类型也不一样

  2. 对SQL语句解析结果的存储会放到SqlSource中,最终执行的SQL语句会放到BoundSql中,对过滤条件的处理在SqlSource中的SqlNode的apply()方法执行,并通过SqlSourceBuilder.parse()来获取最终给数据库的预编译SQL语句

  3. XMLConfigBuilder:解析mapper文件,对于类似<insert><if></if></insert>标签嵌套的标签,生成的SqlSource是一个DynamicSqlSource,里边对于SQL语句和标签保存的是SqlNode节点。其他的生成的SqlSource是RawSqlSource

  4. 在第21步,Configuration.newStatementHandler(Executor, MappedStatement, ParamObject, RowBounds, ResultHandler, BoundSql)中会调用到BaseStatementHandler的构造函数,源码如下:

 1 public abstract class BaseStatementHandler implements StatementHandler {
 2 
 3   protected final Configuration configuration;
 4   protected final ObjectFactory objectFactory;
 5   protected final TypeHandlerRegistry typeHandlerRegistry;
 6   protected final ResultSetHandler resultSetHandler;
 7   protected final ParameterHandler parameterHandler;
 8 
 9   protected final Executor executor;
10   protected final MappedStatement mappedStatement;
11   protected final RowBounds rowBounds;
12 
13   protected BoundSql boundSql;
14 
15   protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
16     this.configuration = mappedStatement.getConfiguration();
17     this.executor = executor;
18     this.mappedStatement = mappedStatement;
19     this.rowBounds = rowBounds;
20 
21     this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
22     this.objectFactory = configuration.getObjectFactory();
23 
24     if (boundSql == null) { // issue #435, get the key before calculating the statement
25       generateKeys(parameterObject);
26       boundSql = mappedStatement.getBoundSql(parameterObject); //此处会转换动态SQL语句,根据传递的参数和判断条件,得出最终的SQL语句(拥有占位符)
27     }
28 
29     this.boundSql = boundSql;
30 
31     this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
32     this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
33   }
34 }
35 
36 public final class MappedStatement {
37  public BoundSql getBoundSql(Object parameterObject) {
38     BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
39     List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
40     if (parameterMappings == null || parameterMappings.size() <= 0) {
41       boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);
42     }
43 
44     // check for nested result maps in parameter mappings (issue #30)
45     for (ParameterMapping pm : boundSql.getParameterMappings()) {
46       String rmId = pm.getResultMapId();
47       if (rmId != null) {
48         ResultMap rm = configuration.getResultMap(rmId);
49         if (rm != null) {
50           hasNestedResultMaps |= rm.hasNestedResultMaps();
51         }
52       }
53     }
54 
55     return boundSql;
56   }
57 }
58 
59 public class DynamicSqlSource implements SqlSource {

    private Configuration configuration;
    private SqlNode rootSqlNode;

60  public BoundSql getBoundSql(Object parameterObject) {
61     DynamicContext context = new DynamicContext(configuration, parameterObject);
62     rootSqlNode.apply(context);
63     SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
64     Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
65     SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
66     BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
67     for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) {
68       boundSql.setAdditionalParameter(entry.getKey(), entry.getValue());
69     }
70     return boundSql;
71   }
72 }

 

总结:

  XMLConfigBuilder知识对mapper.xml做解析,并保存解析的结果,解析的结果可能是静态SQL(没有过滤条件,就一条原生SQL语句(包含占位符)),也可能是动态SQL(拥有过滤条件,需要在执行的时候根据参数来过滤)

  等到真正开始执行的时候(第21步(创建StatementHandler))时,才会根据传入的参数对过滤条件进行处理,得到最终要预处理的SQL语句(包含占位符):

    这一步包含两个最重要的步骤:1. 处理mybatis提供的SqlNode(if,foreach,where,set等)  2. 使用占位符?替换掉固定格式#{xx}

posted @ 2016-01-05 16:35  桦沐  阅读(513)  评论(0编辑  收藏  举报