iBatis源码解读-sqlMap配置解析

前言

书承上文,这一节来分析下SqlMapConfig.xmlsqlMap节点中配置的Hero.xml配置文件,该配置文件中对应了Java实体类对应数据库SQL的映射。

示例

t_hero:

CREATE TABLE `t_hero` (
  `heroId` int(10) NOT NULL AUTO_INCREMENT,
  `name` varchar(10) NOT NULL,
  `type` tinyint(2) NOT NULL,
  PRIMARY KEY (`heroId`)
) ENGINE=InnoDB AUTO_INCREMENT=10003 DEFAULT CHARSET=utf8 COMMENT='英雄表';

Hero.java:

public class Hero implements Serializable {
    private Integer heroId;
    private String name;
    private Integer type;
}

Hero.xml:

<?xml version="1.0" encoding="UTF-8" ?>  
<!DOCTYPE sqlMap        
    PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"        
    "http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap>
    <cacheModel id="heroCache" type="LRU"/>
    <typeAlias alias="Hero" type="com.think.domain.Hero" />
    
    <resultMap id="heroMap" class="Hero">
        <result property="heroId" column="heroId"/>
        <result property="name" column="name"/>
        <result property="type" column="type"/>
    </resultMap>
    
    <parameterMap id="queryHeroMap" class="Hero">
        <parameter property="heroId"/>
    </parameterMap>

    <insert id="addHero" parameterClass="com.think.domain.Hero">
        insert into t_hero values(#heroId#,#name#,#type#)
    </insert>

    <select id="getById" parameterClass="int" resultClass="Hero">
        select * from t_hero where heroId = #heroId#
    </select>

    <delete id="deleteById" parameterClass="int">
        delete from t_hero where heroId=  #heroId#
    </delete>

    <update id="updateById" parameterClass="Hero">
        update t_hero set `name`=#name#,`type`=#type# where heroId = #heroId#
    </update>
</sqlMap>

StartMain:

public class StartMain {
    private static final Logger log = LoggerFactory.getLogger(App.class);
    private static final String CONFIG_FILE = "SqlMapConfig.xml";

    public static void main(String[] args) throws Exception {
        Reader reader = Resources.getResourceAsReader(CONFIG_FILE);
        SqlMapClient sqlMapClient = SqlMapClientBuilder.buildSqlMapClient(reader);
        log.info("Get sql map client: {}", sqlMapClient);
        Hero luban7 = new Hero(10001, "鲁班七号", 3);

        sqlMapClient.insert("addHero", luban7);
        log.info("add Hero: {}", luban7);

        Hero hero = (Hero) sqlMapClient.queryForObject("getById", luban7.getHeroId());
        log.info("hero: {}", hero);

        hero.setName("鲁班8号");
        int ret = sqlMapClient.update("updateById", hero);
        log.info("update Hero: {}", ret);

        hero = (Hero) sqlMapClient.queryForObject("getById", hero.getHeroId());
        log.info("hero: {}", hero);

        ret = sqlMapClient.delete("deleteById", hero.getHeroId());
        log.info("delete hero, {}", ret);
    }
}

源码解析

在源码解析之前,我们先来看看上一节中SqlMapConfig.xml配置文件中注册sqlMap节点解析的源码,位置在com.ibatis.sqlmap.engine.builder.xml.SqlMapConfigParser#addSqlMapNodelets

protected void addSqlMapNodelets() {
    parser.addNodelet("/sqlMapConfig/sqlMap", new Nodelet() {
      public void process(Node node) throws Exception {
        Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
       //指定的配置文件路径
        String resource = attributes.getProperty("resource");
        String url = attributes.getProperty("url");

        Reader reader = null;
        if (resource != null) {
          reader = Resources.getResourceAsReader(resource);
        } else if (url != null) {
          reader = Resources.getUrlAsReader(url);
        } else {
          throw new SqlMapException("The <sqlMap> element requires either a resource or a url attribute.");
        }
       //将配置文件输入流交个SqlMapParser进行解析
        new SqlMapParser(state).parse(reader);
      }
    });
}

我们先来看看SqlMapParser对象的大致结构以及构造方法:

public class SqlMapParser {
  //节点解析器,和SqlMapConfigParser结构一致
  private final NodeletParser parser;
  //数据存储,和SqlMapConfigParser结构一致
  private XmlParserState state;
  //SQL语句解析
  private SqlStatementParser statementParser;

  //通过构造函数传递一个SqlMapConfig中的数据解析存储
  public SqlMapParser(XmlParserState state) {
    this.parser = new NodeletParser();
    this.state = state;
    
    //开启文档校验
    parser.setValidation(true);
    //设置本地类路径的sqlMap解析
    parser.setEntityResolver(new SqlMapClasspathEntityResolver());
    //创建一个Sql语句解析器
    statementParser = new SqlStatementParser(this.state);

    //注册/sqlMapConfig/end()节点
    addSqlMapNodelets();
    ///注册sqlMap/sql节点
    addSqlNodelets();
    ///注册sqlMap/typeAlias节点
    addTypeAliasNodelets();
    //注册/sqlMap/cacheModel节点
    addCacheModelNodelets();
    //注册/sqlMap/parameterMap节点
    addParameterMapNodelets();
    //注册/sqlMap/resultMap节点
    addResultMapNodelets();
    //注册/sqlMap/statement节点(包括/sqlMap/insert,/sqlMap/update,/sqlMap/delete,/sqlMap/select,/sqlMap/procedure节点)
    addStatementNodelets();
  }   
}

addSqlMapNodelets:

private void addSqlMapNodelets() {
    parser.addNodelet("/sqlMap", new Nodelet() {
      public void process(Node node) throws Exception {
        //获取节点上的属性
        Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
        //设置命名空间
        state.setNamespace(attributes.getProperty("namespace"));
      }
    });
}

addSqlNodelets:

private void addSqlNodelets() {
    parser.addNodelet("/sqlMap/sql", new Nodelet() {
      public void process(Node node) throws Exception {
        //解析标签上的节点属性
        Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
        //获取该标签的id
        String id = attributes.getProperty("id");
        //如果有命名空间则添加上命名空间
        if (state.isUseStatementNamespaces()) {
          id = state.applyNamespace(id);
        }
        //重复id检查
        if (state.getSqlIncludes().containsKey(id)) {
          throw new SqlMapException("Duplicate <sql>-include '" + id + "' found.");
        } else {
          //将该sql放入到sqlIncludes的Map集合中
          state.getSqlIncludes().put(id, node);
        }
      }
    });
}

addTypeAliasNodelets:

private void addTypeAliasNodelets() {
    parser.addNodelet("/sqlMap/typeAlias", new Nodelet() {
      public void process(Node node) throws Exception {
        //货物节点属性
        Properties prop = NodeletUtils.parseAttributes(node, state.getGlobalProps());
        //别名
        String alias = prop.getProperty("alias");
        //类全限定名
        String type = prop.getProperty("type");
        //将其放入到SqlMapConfiguration的TypeHandlerFactory对象中typeAliases集合中
        state.getConfig().getTypeHandlerFactory().putTypeAlias(alias, type);
      }
    });
}

addTypeAliasNodelets用于将一个类名定义一个别名,后期可以减少输入一长串的字符。

addCacheModelNodelets:

private void addCacheModelNodelets() {
    parser.addNodelet("/sqlMap/cacheModel", new Nodelet() {
      public void process(Node node) throws Exception {
        //获取节点属性
        Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
        //缓存节点id
        String id = state.applyNamespace(attributes.getProperty("id"));
        //缓存类型(FIFO、LRU、MEMORY、OSCACHE)
        String type = attributes.getProperty("type");
        //该缓存是否只读
        String readOnlyAttr = attributes.getProperty("readOnly");
        Boolean readOnly = readOnlyAttr == null || readOnlyAttr.length() <= 0 ? null : new Boolean("true".equals(readOnlyAttr));
        //该缓存是否可序列化
        String serializeAttr = attributes.getProperty("serialize");
        Boolean serialize = serializeAttr == null || serializeAttr.length() <= 0 ? null : new Boolean("true".equals(serializeAttr));
        //通过该缓存类型定位到具体的缓存全限定类,该缓存的注册在SqlMapConfiguration#registerDefaultTypeAliases
        type = state.getConfig().getTypeHandlerFactory().resolveAlias(type);
        //加载该class
        Class clazz = Resources.classForName(type);
        if (readOnly == null) {
          readOnly = Boolean.TRUE;
        }
        if (serialize == null) {
          serialize = Boolean.FALSE;
        }
        //实例化一个CacheModel并将其添加到SqlMapExecutorDelegate的cacheModels的Map集合中,并返回CacheModelConfig实例对象
        CacheModelConfig cacheConfig = state.getConfig().newCacheModelConfig(id, (CacheController) Resources.instantiate(clazz), readOnly.booleanValue(), serialize.booleanValue());
        //设置当前的CacheModelConfig
        state.setCacheConfig(cacheConfig);
      }
    });
    //用于处理cacheModel标签结束后调用
    parser.addNodelet("/sqlMap/cacheModel/end()", new Nodelet() {
      public void process(Node node) throws Exception {
        //设置当前CacheModelConfig的缓存属性
        state.getCacheConfig().setControllerProperties(state.getCacheProps());
      }
    });
    //用于处理cacheModel下节点的property属性节点
    parser.addNodelet("/sqlMap/cacheModel/property", new Nodelet() {
      public void process(Node node) throws Exception {
        //获取节点属性
        Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
        //属性名
        String name = attributes.getProperty("name");
        //属性值
        String value = NodeletUtils.parsePropertyTokens(attributes.getProperty("value"), state.getGlobalProps());
        //将节点的属性名和属性值放入到Properties集合中
        state.getCacheProps().setProperty(name, value);
      }
    });
    //用于处理cacheModel下节点的flushOnExecute属性节点(语句执行触发刷新缓存)
    parser.addNodelet("/sqlMap/cacheModel/flushOnExecute", new Nodelet() {
      public void process(Node node) throws Exception {
        //获取节点属性
        Properties childAttributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
        //语句id
        String statement = childAttributes.getProperty("statement");
        //添加执行该语句时触发缓存刷新
        state.getCacheConfig().addFlushTriggerStatement(statement);
      }
    });
    //用于处理cacheModel下节点的flushInterval属性节点(缓存刷新间隔)
    parser.addNodelet("/sqlMap/cacheModel/flushInterval", new Nodelet() {
      public void process(Node node) throws Exception {
        //节点属性
        Properties childAttributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
        //间隔时间(毫秒)
        int milliseconds = childAttributes.getProperty("milliseconds") == null ? 0 : Integer.parseInt(childAttributes.getProperty("milliseconds"));
        //间隔时间(秒)
        int seconds = childAttributes.getProperty("seconds") == null ? 0 : Integer.parseInt(childAttributes.getProperty("seconds"));
        //间隔时间(分)
        int minutes = childAttributes.getProperty("minutes") == null ? 0 : Integer.parseInt(childAttributes.getProperty("minutes"));
         //间隔时间(小时)
        int hours = childAttributes.getProperty("hours") == null ? 0 : Integer.parseInt(childAttributes.getProperty("hours"));
        //设置该缓存的刷新间隔
        state.getCacheConfig().setFlushInterval(hours, minutes, seconds, milliseconds);
      }
    });
}

可以看到该方法是用于配置iBatis的一个缓存。

addParameterMapNodelets:

private void addParameterMapNodelets() {
    //处理/sqlMap/parameterMap节点结束
    parser.addNodelet("/sqlMap/parameterMap/end()", new Nodelet() {
      public void process(Node node) throws Exception {
        state.setParamConfig(null);
      }
    });
    //处理/sqlMap/parameterMap节点
    parser.addNodelet("/sqlMap/parameterMap", new Nodelet() {
      public void process(Node node) throws Exception {
        //获取节点属性
        Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
        //节点id
        String id = state.applyNamespace(attributes.getProperty("id"));
        //参数对应的全限定类名/别名
        String parameterClassName = attributes.getProperty("class");
        //通过别名定位java全限定类名
        parameterClassName = state.getConfig().getTypeHandlerFactory().resolveAlias(parameterClassName);
        //实例化一个参数集合配置对象(内部实例化了ParameterMap对象并将其添加到SqlMapExecutorDelegate中parameterMaps集合中)
        ParameterMapConfig paramConf = state.getConfig().newParameterMapConfig(id, Resources.classForName(parameterClassName));
        state.setParamConfig(paramConf);
      }
    });
    //解析/sqlMap/parameterMap/parameter节点
    parser.addNodelet("/sqlMap/parameterMap/parameter", new Nodelet() {
      public void process(Node node) throws Exception {
        //解析标签属性
        Properties childAttributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
        //属性名
        String propertyName = childAttributes.getProperty("property");
        //数据库类型
        String jdbcType = childAttributes.getProperty("jdbcType");
        //类型名
        String type = childAttributes.getProperty("typeName");
        //java对应的数据类型
        String javaType = childAttributes.getProperty("javaType");
        //结果集合
        String resultMap = state.applyNamespace(childAttributes.getProperty("resultMap"));
        String nullValue = childAttributes.getProperty("nullValue");
        String mode = childAttributes.getProperty("mode");
        //类型处理器
        String callback = childAttributes.getProperty("typeHandler");
        //浮点数精度
        String numericScaleProp = childAttributes.getProperty("numericScale");

        //通过别名定位类型处理器
        callback = state.getConfig().getTypeHandlerFactory().resolveAlias(callback);
        Object typeHandlerImpl = null;
        if (callback != null) {
          typeHandlerImpl = Resources.instantiate(callback);
        }

        javaType = state.getConfig().getTypeHandlerFactory().resolveAlias(javaType);
        Class javaClass = null;
        if (javaType != null && javaType.length() > 0) {
          javaClass = Resources.classForName(javaType);
        }

        Integer numericScale = null;
        if (numericScaleProp != null) {
          numericScale = new Integer(numericScaleProp);
        }
        //将参数字段添加到ParameterMapConfig对象的parameterMappingList集合中(用于将数据库字段和java属性字段映射过程)
        state.getParamConfig().addParameterMapping(propertyName, javaClass, jdbcType, nullValue, mode, type, numericScale, typeHandlerImpl, resultMap);
      }
    });
}

addResultMapNodelets:

private void addResultMapNodelets() {
    //注册/sqlMap/resultMap节点结束处理
    parser.addNodelet("/sqlMap/resultMap/end()", new Nodelet() {
      public void process(Node node) throws Exception {
        state.getConfig().getErrorContext().setMoreInfo(null);
        state.getConfig().getErrorContext().setObjectId(null);
      }
    });
    //注册/sqlMap/resultMap节点处理
    parser.addNodelet("/sqlMap/resultMap", new Nodelet() {
      public void process(Node node) throws Exception {
        //节点属性
        Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
        //结果集id
        String id = state.applyNamespace(attributes.getProperty("id"));
        //结果对应的java实体类(别名或者全限定类名) 
        String resultClassName = attributes.getProperty("class");
        //继承的结果集
        String extended = state.applyNamespace(attributes.getProperty("extends"));
        String xmlName = attributes.getProperty("xmlName");
        String groupBy = attributes.getProperty("groupBy");

        //通过别名定位java全限定类名
        resultClassName = state.getConfig().getTypeHandlerFactory().resolveAlias(resultClassName);
        //加载类
        Class resultClass = Resources.classForName(resultClassName);
        //实例化ResultMapConfig对象,内部实例化ResultMap并将其添加到SqlMapExecutorDelegate对象的resultMaps集合中
        ResultMapConfig resultConf = state.getConfig().newResultMapConfig(id, resultClass, groupBy, extended, xmlName);
        state.setResultConfig(resultConf);
      }
    });
    //注册/sqlMap/resultMap/result节点处理
    parser.addNodelet("/sqlMap/resultMap/result", new Nodelet() {
      public void process(Node node) throws Exception {
        //获取节点属性
        Properties childAttributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
        //属性名
        String propertyName = childAttributes.getProperty("property");
        String nullValue = childAttributes.getProperty("nullValue");
        String jdbcType = childAttributes.getProperty("jdbcType");
        String javaType = childAttributes.getProperty("javaType");
        //数据库列名
        String columnName = childAttributes.getProperty("column");
        //数据库列索引
        String columnIndexProp = childAttributes.getProperty("columnIndex");
        String statementName = childAttributes.getProperty("select");
        String resultMapName = childAttributes.getProperty("resultMap");
        String callback = childAttributes.getProperty("typeHandler");
        String notNullColumn = childAttributes.getProperty("notNullColumn");

        Class javaClass = null;
        javaType = state.getConfig().getTypeHandlerFactory().resolveAlias(javaType);
        if (javaType != null && javaType.length() > 0) {
          javaClass = Resources.classForName(javaType);
        }

        Object typeHandlerImpl = null;
        if (callback != null && callback.length() > 0) {
          callback = state.getConfig().getTypeHandlerFactory().resolveAlias(callback);
          typeHandlerImpl = Resources.instantiate(callback);
        }

        Integer columnIndex = null;
        if (columnIndexProp != null) {
          columnIndex = new Integer(columnIndexProp);
        }
        //将该数据库列和java属性对应实例化一个ResultMapping添加到ResultMapConfig对象中
        state.getResultConfig().addResultMapping(propertyName, columnName, columnIndex, javaClass, jdbcType, nullValue, notNullColumn, statementName, resultMapName, typeHandlerImpl);
      }
    });
    //注册/sqlMap/resultMap/discriminator/subMap节点
    parser.addNodelet("/sqlMap/resultMap/discriminator/subMap", new Nodelet() {
      public void process(Node node) throws Exception {
        Properties childAttributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
        String value = childAttributes.getProperty("value");
        String resultMap = childAttributes.getProperty("resultMap");
        resultMap = state.applyNamespace(resultMap);
        state.getResultConfig().addDiscriminatorSubMap(value, resultMap);
      }
    });
    //注册/sqlMap/resultMap/discriminator节点
    parser.addNodelet("/sqlMap/resultMap/discriminator", new Nodelet() {
      public void process(Node node) throws Exception {
        Properties childAttributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
        String nullValue = childAttributes.getProperty("nullValue");
        String jdbcType = childAttributes.getProperty("jdbcType");
        String javaType = childAttributes.getProperty("javaType");
        String columnName = childAttributes.getProperty("column");
        String columnIndexProp = childAttributes.getProperty("columnIndex");
        String callback = childAttributes.getProperty("typeHandler");

        Class javaClass = null;
        javaType = state.getConfig().getTypeHandlerFactory().resolveAlias(javaType);
        if (javaType != null && javaType.length() > 0) {
          javaClass = Resources.classForName(javaType);
        }

        Object typeHandlerImpl = null;
        if (callback != null && callback.length() > 0) {
          callback = state.getConfig().getTypeHandlerFactory().resolveAlias(callback);
          typeHandlerImpl = Resources.instantiate(callback);
        }

        Integer columnIndex = null;
        if (columnIndexProp != null) {
          columnIndex = new Integer(columnIndexProp);
        }

        state.getResultConfig().setDiscriminator(columnName, columnIndex, javaClass, jdbcType, nullValue, typeHandlerImpl);
      }
    });
}

addStatementNodelets:

protected void addStatementNodelets() {
    //注册/sqlMap/statement标签的解析处理
    parser.addNodelet("/sqlMap/statement", new Nodelet() {
      public void process(Node node) throws Exception {
        statementParser.parseGeneralStatement(node, new MappedStatement());
      }
    });
    //注册/sqlMap/insert标签的解析处理
    parser.addNodelet("/sqlMap/insert", new Nodelet() {
      public void process(Node node) throws Exception {
        statementParser.parseGeneralStatement(node, new InsertStatement());
      }
    });
    //注册/sqlMap/update标签的解析处理
    parser.addNodelet("/sqlMap/update", new Nodelet() {
      public void process(Node node) throws Exception {
        statementParser.parseGeneralStatement(node, new UpdateStatement());
      }
    });
    //注册/sqlMap/delete标签的解析处理
    parser.addNodelet("/sqlMap/delete", new Nodelet() {
      public void process(Node node) throws Exception {
        statementParser.parseGeneralStatement(node, new DeleteStatement());
      }
    });
    //注册/sqlMap/select标签的解析处理
    parser.addNodelet("/sqlMap/select", new Nodelet() {
      public void process(Node node) throws Exception {
        statementParser.parseGeneralStatement(node, new SelectStatement());
      }
    });
    //注册/sqlMap/procedure标签的解析处理
    parser.addNodelet("/sqlMap/procedure", new Nodelet() {
      public void process(Node node) throws Exception {
        statementParser.parseGeneralStatement(node, new ProcedureStatement());
      }
    });
}

因为关于SQL语句的解析都是交给com.ibatis.sqlmap.engine.builder.xml.SqlStatementParser#parseGeneralStatement,所以我们来看下其内部实现:

public void parseGeneralStatement(Node node, MappedStatement statement) {
    // 获取节点上的属性
    Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
    //语句id
    String id = attributes.getProperty("id");
    //参数集合名
    String parameterMapName = state.applyNamespace(attributes.getProperty("parameterMap"));
    //参数类名
    String parameterClassName = attributes.getProperty("parameterClass");
    //映射结果集名
    String resultMapName = attributes.getProperty("resultMap");
    //映射结果类名
    String resultClassName = attributes.getProperty("resultClass");
    //缓存名
    String cacheModelName = state.applyNamespace(attributes.getProperty("cacheModel"));
    String xmlResultName = attributes.getProperty("xmlResultName");
    String resultSetType = attributes.getProperty("resultSetType");
    String fetchSize = attributes.getProperty("fetchSize");
    String allowRemapping = attributes.getProperty("remapResults");
    //语句执行超时时间
    String timeout = attributes.getProperty("timeout");
    //是否使用了命名空间
    if (state.isUseStatementNamespaces()) {
      id = state.applyNamespace(id);
    }
    //处理结果集合名
    String[] additionalResultMapNames = null;
    if (resultMapName != null) {
      additionalResultMapNames = state.getAllButFirstToken(resultMapName);
      resultMapName = state.getFirstToken(resultMapName);
      resultMapName = state.applyNamespace(resultMapName);
      //处理多个的情况
      for (int i = 0; i < additionalResultMapNames.length; i++) {
        additionalResultMapNames[i] = state.applyNamespace(additionalResultMapNames[i]);
      }
    }
    //处理结果类
    String[] additionalResultClassNames = null;
    if (resultClassName != null) {
      additionalResultClassNames = state.getAllButFirstToken(resultClassName);
      resultClassName = state.getFirstToken(resultClassName);
    }
    //处理多个的情况
    Class[] additionalResultClasses = null;
    if (additionalResultClassNames != null) {
      additionalResultClasses = new Class[additionalResultClassNames.length];
      for (int i = 0; i < additionalResultClassNames.length; i++) {
        additionalResultClasses[i] = resolveClass(additionalResultClassNames[i]);
      }
    }

    Class parameterClass = resolveClass(parameterClassName);
    Class resultClass = resolveClass(resultClassName);

    Integer timeoutInt = timeout == null ? null : new Integer(timeout);
    Integer fetchSizeInt = fetchSize == null ? null : new Integer(fetchSize);
    boolean allowRemappingBool = "true".equals(allowRemapping);

    //实例化MappedStatementConfig对象
    MappedStatementConfig statementConf = state.getConfig().newMappedStatementConfig(id, statement,
        new XMLSqlSource(state, node), parameterMapName, parameterClass, resultMapName, additionalResultMapNames, resultClass, additionalResultClasses, resultSetType, fetchSizeInt, allowRemappingBool, timeoutInt, cacheModelName, xmlResultName);

    findAndParseSelectKey(node, statementConf);
}

newMappedStatementConfig:

public MappedStatementConfig newMappedStatementConfig(String id, MappedStatement statement, SqlSource processor,  String parameterMapName, Class parameterClass, String resultMapName, String[] additionalResultMapNames, Class resultClass, Class[] additionalResultClasses, String resultSetType, Integer fetchSize, boolean allowRemapping, Integer timeout, String cacheModelName, String xmlResultName) {
    return new MappedStatementConfig(this, id, statement, processor, parameterMapName, parameterClass, resultMapName, additionalResultMapNames, resultClass, additionalResultClasses, cacheModelName, resultSetType, fetchSize, allowRemapping, timeout, defaultStatementTimeout, xmlResultName);
}

MappedStatementConfig构造函数:

MappedStatementConfig(SqlMapConfiguration config, String id, MappedStatement statement, SqlSource processor, String parameterMapName, Class parameterClass, String resultMapName, String[] additionalResultMapNames, Class resultClass, Class[] additionalResultClasses, String cacheModelName, String resultSetType, Integer fetchSize, boolean allowRemapping, Integer timeout, Integer defaultStatementTimeout, String xmlResultName) {
    this.client = config.getClient();
    SqlMapExecutorDelegate delegate = client.getDelegate();
    this.typeHandlerFactory = config.getTypeHandlerFactory();
    if (resultMapName != null) {
      //根据结果集名获取结果集
      statement.setResultMap(client.getDelegate().getResultMap(resultMapName));
      //处理多个结果集的情况
      if (additionalResultMapNames != null) {
        for (int i = 0; i < additionalResultMapNames.length; i++) {
          statement.addResultMap(client.getDelegate().getResultMap(additionalResultMapNames[i]));
        }
      }
    }
    //处理参数集合
    if (parameterMapName != null) {
      statement.setParameterMap(client.getDelegate().getParameterMap(parameterMapName));
    }
    //设置语句id
    statement.setId(id);
    statement.setResource(errorContext.getResource());
    if (resultSetType != null) {
      if ("FORWARD_ONLY".equals(resultSetType)) {
        statement.setResultSetType(new Integer(ResultSet.TYPE_FORWARD_ONLY));
      } else if ("SCROLL_INSENSITIVE".equals(resultSetType)) {
        statement.setResultSetType(new Integer(ResultSet.TYPE_SCROLL_INSENSITIVE));
      } else if ("SCROLL_SENSITIVE".equals(resultSetType)) {
        statement.setResultSetType(new Integer(ResultSet.TYPE_SCROLL_SENSITIVE));
      }
    }
    if (fetchSize != null) {
      statement.setFetchSize(fetchSize);
    }

    // 从属性或映射设置参数类(确保匹配)
    ParameterMap parameterMap = statement.getParameterMap();
    if (parameterMap == null) {
      statement.setParameterClass(parameterClass);
    } else {
      statement.setParameterClass(parameterMap.getParameterClass());
    }

    // 处理SQL语句,包括内联参数集合
    Sql sql = processor.getSql();
    setSqlForStatement(statement, sql);

    // 设置空结果映射或自动结果映射
    ResultMap resultMap = (ResultMap) statement.getResultMap();
    if (resultMap == null && resultClass == null) {
      statement.setResultMap(null);
    } else if (resultMap == null) {
      resultMap = buildAutoResultMap(allowRemapping, statement, resultClass, xmlResultName);
      statement.setResultMap(resultMap);
      if (additionalResultClasses != null) {
        for (int i = 0; i < additionalResultClasses.length; i++) {
          statement.addResultMap(buildAutoResultMap(allowRemapping, statement, additionalResultClasses[i], xmlResultName));
        }
      }

    }
    //设置执行语句超时时间
    statement.setTimeout(defaultStatementTimeout);
    if (timeout != null) {
        statement.setTimeout(timeout);
    }
    //设置SqlMap客户端
    statement.setSqlMapClient(client);
    //如果有使用缓存则包装成CachingStatement
    if (cacheModelName != null && cacheModelName.length() > 0 && client.getDelegate().isCacheModelsEnabled()) {
      CacheModel cacheModel = client.getDelegate().getCacheModel(cacheModelName);
      mappedStatement = new CachingStatement(statement, cacheModel);
    } else {
      mappedStatement = statement;
    }
    rootStatement = statement;
    //将该语句添加到SqlMapExecutorDelegate的mappedStatements集合中
    delegate.addMappedStatement(mappedStatement);
}

到此为止,关于sqlMap节点的解析就完成了。

总结

sqlMap节点的解析其实和sqlMapConfig.xml配置文件差不多,都是注册对应的节点,然后进行解析。我们常用的SQL语句分别使用selectdeleteupdateinsert来进行处理,还有特殊的statement和存储过程procedure。将对应的语句进行解析然后拼凑成一个完整的MappedStatement对象,然后放到SqlMapExecutorDelegate对象的mappedStatements集合中。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271