美文网首页
iBatis源码解读-sqlMap配置解析

iBatis源码解读-sqlMap配置解析

作者: 安静点就睡吧 | 来源:发表于2020-07-17 12:01 被阅读0次

    前言

    书承上文,这一节来分析下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集合中。

    相关文章

      网友评论

          本文标题:iBatis源码解读-sqlMap配置解析

          本文链接:https://www.haomeiwen.com/subject/sscghktx.html