Mybatis第三天 ---- 加载Mapper配置文件

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wxy540843763/article/details/80738574

上回说到,加载mybatis-config.xml.今天说说,加载Mapper文件。

在org.apache.ibatis.builder这个包中,是全部的Builder。这里还有两个子包。xml和annotion,就是xml的加载和注解的加载了。

接下来就看下这个加载Mapper文件的builder吧。XMLMapperBuilder.java

其构造方法有五个,两个已经过时了。

@Deprecated
public XMLMapperBuilder(Reader reader, Configuration configuration, String resource, Map<String, XNode> sqlFragments, String namespace) {
  this(reader, configuration, resource, sqlFragments);
  this.builderAssistant.setCurrentNamespace(namespace);
}

@Deprecated
public XMLMapperBuilder(Reader reader, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
  this(new XPathParser(reader, true, configuration.getVariables(), new XMLMapperEntityResolver()),
      configuration, resource, sqlFragments);
}

public XMLMapperBuilder(InputStream inputStream, Configuration configuration, String resource, Map<String, XNode> sqlFragments, String namespace) {
  this(inputStream, configuration, resource, sqlFragments);
  this.builderAssistant.setCurrentNamespace(namespace);
}

public XMLMapperBuilder(InputStream inputStream, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
  this(new XPathParser(inputStream, true, configuration.getVariables(), new XMLMapperEntityResolver()),
      configuration, resource, sqlFragments);
}

private XMLMapperBuilder(XPathParser parser, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
  super(configuration);
  this.builderAssistant = new MapperBuilderAssistant(configuration, resource);
  this.parser = parser;
  this.sqlFragments = sqlFragments;
  this.resource = resource;
}


接下来就是本类中最重要的方法:parse()

首先说一下Mapper xml文件吧。

Sql映射文件,只有很少的几个元素:

  • cache – 给定命名空间的缓存配置。
  • cache-ref – 其他命名空间缓存配置的引用。
  • resultMap – 是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象。
  • parameterMap – 已废弃!老式风格的参数映射。内联参数是首选,这个元素可能在将来被移除,这里不会记录。
  • sql – 可被其他语句引用的可重用语句块。
  • insert – 映射插入语句
  • update – 映射更新语句
  • delete – 映射删除语句
  • select – 映射查询语句

还是先放一个比较完整的mapper.xml文件。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.cyou.falsework.request.mapper.DailyTodoMapper">


<select id="selectPerson" parameterType="int" resultType="hashmap">
  SELECT * FROM PERSON WHERE ID = #{id}
</select>
<select id="selectPerson" parameterType="int" parameterMap="deprecated"
  resultType="hashmap" resultMap="personResultMap" flushCache="false" useCache="true"
  timeout="10000" fetchSize="256" statementType="PREPARED" resultSetType="FORWARD_ONLY">
  SELECT * FROM PERSON WHERE ID = #{id}
</select>




<insert
  id="insertAuthor"
  parameterType="domain.blog.Author"
  flushCache="true"
  statementType="PREPARED"
  keyProperty=""
  keyColumn=""
  useGeneratedKeys=""
  timeout="20">


<update
  id="updateAuthor"
  parameterType="domain.blog.Author"
  flushCache="true"
  statementType="PREPARED"
  timeout="20">


<delete
  id="deleteAuthor"
  parameterType="domain.blog.Author"
  flushCache="true"
  statementType="PREPARED"
  timeout="20">


  <selectKey
  keyProperty="id"
  resultType="int"
  order="BEFORE"
  statementType="PREPARED">
    select CAST(RANDOM()*1000000 as INTEGER) a from SYSIBM.SYSDUMMY1
  </selectKey>




<resultMap id="userResultMap" type="User">
  <id property="id" column="user_id" />
  <result property="username" column="user_name"/>
  <result property="password" column="hashed_password"/>
</resultMap>


<resultMap id="blogResult" type="Blog">
  <id property="id" column="blog_id" />
  <result property="title" column="blog_title"/>
  <association property="author" javaType="Author">
    <id property="id" column="author_id"/>
    <result property="username" column="author_username"/>
    <result property="password" column="author_password"/>
    <result property="email" column="author_email"/>
    <result property="bio" column="author_bio"/>
  </association>
</resultMap>
<cache
  eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"/>


</mapper>


来吧,看一下parse()这个方法:

public void parse() {
    // 判断该配置文件(resource)是否已经被加载。
    if (!configuration.isResourceLoaded(resource)) {
        // 如果没有被加载。先读取整个mapper文件。
        configurationElement(parser.evalNode("/mapper"));
        // 把这个已经加载的配置文件(资源,resource)放到configuration这个Set中。
        configuration.addLoadedResource(resource);
        // 为这个命名空间绑定映射。
        bindMapperForNamespace();
    }

    // 解析ResultMaps
    parsePendingResultMaps();
    // 解析缓存
    parsePendingCacheRefs();
    // 解析Statements(Sql语句)
    parsePendingStatements();
}

第一次加载的时候,肯定会进入这个if里面。那么它就会 解析所有的mapper文件。并且把所有解析过的 resource,也就是mapper文件放入configuration的一个Set(loaderResources)中,s说明这个mapper文件已经被加载过了。那么来看一下是如何加载mapper这个文件的。

/**
 * 加载**Mapper.xml文件。将该配置文件中的节点放入configuration中。
 * @param context
 */
private void configurationElement(XNode context) {
    try {
        String namespace = context.getStringAttribute("namespace");
        if (namespace == null || namespace.equals("")) {
            throw new BuilderException("Mapper's namespace cannot be empty");
        }
        builderAssistant.setCurrentNamespace(namespace);
        // 解析cache-ref节点
        cacheRefElement(context.evalNode("cache-ref"));
        // 解析cache节点
        cacheElement(context.evalNode("cache"));
        // 解析parameterMap节点
        parameterMapElement(context.evalNodes("/mapper/parameterMap"));
        // 解析resultMap节点
        resultMapElements(context.evalNodes("/mapper/resultMap"));
        // 解析sql节点
        sqlElement(context.evalNodes("/mapper/sql"));
        // 解析selectinsertupdatedelete
        buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
    } catch (Exception e) {
        throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e);
    }
}
 
 

回到parse()方法中:看到一个重要的方法:parsePendingResultMaps().

/**
 * 解析ResultMaps
 * parse()方法中,已经将mapper文件中的所有放入了configuration中,
 * 接下来就是具体的从configuration中取出来,进行进一步的解析。
 */
private void parsePendingResultMaps() {
    // configuration中取出待解析的resultMap
    Collection<ResultMapResolver> incompleteResultMaps = configuration.getIncompleteResultMaps();
    //
    synchronized (incompleteResultMaps) {
        Iterator<ResultMapResolver> iter = incompleteResultMaps.iterator();
        // 逐个解析ResultMap
        while (iter.hasNext()) {
            try {
                // 具体的解析方法是:org.apache.ibatis.builder.MapperBuilderAssistant.addResultMap()方法。
                iter.next().resolve();
                iter.remove();
            } catch (IncompleteElementException e) {
                // ResultMap is still missing a resource...
            }
        }
    }
}

跟着看一下:MapperBuilderAssistant.addResultMap方法:

public ResultMap addResultMap(String id, Class<?> type, String extend, Discriminator discriminator, List<ResultMapping> resultMappings, Boolean autoMapping) {
    id = applyCurrentNamespace(id, false);
    extend = applyCurrentNamespace(extend, true);

    if (extend != null) {
        if (!configuration.hasResultMap(extend)) {
            throw new IncompleteElementException("Could not find a parent resultmap with id '" + extend + "'");
        }
        ResultMap resultMap = configuration.getResultMap(extend);
        List<ResultMapping> extendedResultMappings = new ArrayList<>(resultMap.getResultMappings());
        extendedResultMappings.removeAll(resultMappings);
        // Remove parent constructor if this resultMap declares a constructor.
        boolean declaresConstructor = false;
        for (ResultMapping resultMapping : resultMappings) {
            if (resultMapping.getFlags().contains(ResultFlag.CONSTRUCTOR)) {
                declaresConstructor = true;
                break;
            }
        }
        if (declaresConstructor) {
            Iterator<ResultMapping> extendedResultMappingsIter = extendedResultMappings.iterator();
            while (extendedResultMappingsIter.hasNext()) {
                if (extendedResultMappingsIter.next().getFlags().contains(ResultFlag.CONSTRUCTOR)) {
                    extendedResultMappingsIter.remove();
                }
            }
        }
        resultMappings.addAll(extendedResultMappings);
    }
    ResultMap resultMap = new ResultMap.Builder(configuration, id, type, resultMappings, autoMapping)
            .discriminator(discriminator)
            .build();
    configuration.addResultMap(resultMap);
    return resultMap;
}







猜你喜欢

转载自blog.csdn.net/wxy540843763/article/details/80738574