栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Mybatis MappedStatement原理

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Mybatis MappedStatement原理

我们知道一个MappedStatement对象表示的是XML中的一个SQL信息,主要属性如下。

public final class MappedStatement {
  //sql的ID,mapper接口的方法名
  private String id;
  //SQL超时时间
  private Integer timeout;
  //Statement的类型,STATEMENT/PREPARE/CALLABLE,默认PREPARE
  private StatementType statementType;
  //结果集类型,FORWARD_ONLY/SCROLL_SENSITIVE/SCROLL_INSENSITIVE 
  private ResultSetType resultSetType;
  //表示解析出来的SQL
  private SqlSource sqlSource;
  //缓存,查询用
  private Cache cache;
  //对应的ResultMap
  private List resultMaps;
  // 是否刷新缓存
  private boolean flushCacheRequired;
  // 是否使用二级缓存,一级缓存是session的
  private boolean useCache;
  //SQL类型,select|insert|update|delete"
  private SqlCommandType sqlCommandType;
  //数据库ID
  private String databaseId;
  }

Mybatis 通过解析 XML,生成 sql 对应的 MappedStatement ,并放入 SqlSessionTemplate 中 configuration 类属性中,等正真执行 mapper 接口中的方法时,根据mapper接口的全类名+方法名作为key,会从 configuration 中找到对应的 mappedStatement ,然后进行后续的操作。

本文以mybatisplus为例,大体涉及到的类有MybatisPlusAutoConfiguration、MybatisSqlSessionFactoryBean、XMLMapperBuilder、MapperBuilderAssistant

MybatisPlusAutoConfiguration.java

首先加入mybatisplus的依赖后,sping boot找到com.baodidou.mybatisplus.autoconfigure包下面的META-INF/spring.factory,根据自动装配去加载MybatisPlusAutoConfiguration里面的属性,

@Configuration
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties({MybatisPlusProperties.class})
@AutoConfigureAfter({DataSourceAutoConfiguration.class, MybatisPlusLanguageDriverAutoConfiguration.class})
public class MybatisPlusAutoConfiguration implements InitializingBean {


    // 初始化SqlSessionFactory,MappedStatement生成的入口
    @Bean
    @ConditionalOnMissingBean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean(); 
        return factory.getObject();
    }
}
MybatisSqlSessionFactoryBean.java

调用MybatisSqlSessionFactoryBean里面的getObject(),进而调用this.afterPropertiesSet(),然后调用buildSqlSessionFactory()

public class MybatisSqlSessionFactoryBean implements FactoryBean, InitializingBean, ApplicationListener {

  public SqlSessionFactory getObject() throws Exception {
        if (this.sqlSessionFactory == null) {
            this.afterPropertiesSet();
        }

        return this.sqlSessionFactory;
    }
   
  @Override
    public void afterPropertiesSet() throws Exception {
        this.sqlSessionFactory = buildSqlSessionFactory();
    }	

	 protected SqlSessionFactory buildSqlSessionFactory() throws Exception {
	    // this.mapperLocations 项目配置的所有mybatis xml文件 比如: 项目路径targetclassesmapperSelectUserMapper.xml
	    if (this.mapperLocations != null) {
                for (Resource mapperLocation : this.mapperLocations) {
                   // 解析xml
                    xmlMapperBuilder.parse();        
                }   
        } 
	 }
	 
}

XMLMapperBuilder.java

调用XMLMapperBuilder的parse(),关键方法 configurationElement(parser.evalNode("/mapper"));

public class XMLMapperBuilder extends BaseBuilder {
  public void parse() {
    if (!configuration.isResourceLoaded(resource)) {
	 //从mapper根节点开始解析
	  configurationElement(parser.evalNode("/mapper"));
    }


  
private void configurationElement(XNode context) {
      //解析mapper的namespace
      String namespace = context.getStringAttribute("namespace");
      //解析resultMap节点
      resultMapElements(context.evalNodes("/mapper/resultMap"));
      //解析SQL语句(select|insert|update|delete节点) 
      buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
  }
  
  private void buildStatementFromContext(List list, String requiredDatabaseId) {
    //遍历XNode
    for (XNode context : list) {
      try {
      //解析StatementNode
        statementParser.parseStatementNode();
      } catch (IncompleteElementException e) {
        //解析报错的,在parsePendingStatements方法中再解析
        configuration.addIncompleteStatement(statementParser);
      }
    }
  }
  
  public void parseStatementNode() {
    //获取sql标签的id
    String id = context.getStringAttribute("id");
	// 获取sql的类型,select|insert|update|delete
    String nodeName = context.getNode().getNodeName();
    boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
	// 是否刷新缓存,默认查询不刷新
    boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect);
	// 是否对该语句进行二级缓存;  select 默认为 true。
    boolean useCache = context.getBooleanAttribute("useCache", isSelect);
    SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
	// statementType 未设置默认PREPARED 
    StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
    // 参数	
	String parameterMap = context.getStringAttribute("parameterMap");
	// 返回值类型
    String resultType = context.getStringAttribute("resultType");
	
	/通过buildAssistant将解析得到的参数设置构造成MappedStatement对象
	   builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
        fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
        resultSetTypeEnum, flushCache, useCache, resultOrdered,
        keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
  }
}
MapperBuilderAssistant.java

最后调用MapperBuilderAssistant的addMappedStatement方法完成向configuration添加MappedStatement

 public class MapperBuilderAssistant extends BaseBuilder { 
    public MappedStatement addMappedStatement(
      String id,
      SqlSource sqlSource,
      StatementType statementType,
      SqlCommandType sqlCommandType,
      Integer fetchSize,
      Integer timeout,
      String parameterMap,
      Class parameterType,
      String resultMap,
      Class resultType,
      ResultSetType resultSetType,
      boolean flushCache,
      boolean useCache,
      boolean resultOrdered,
      KeyGenerator keyGenerator,
      String keyProperty,
      String keyColumn,
      String databaseId,
      LanguageDriver lang,
      String resultSets) {

    if (unresolvedCacheRef) {
      throw new IncompleteElementException("Cache-ref not yet resolved");
    }

    id = applyCurrentNamespace(id, false);
    boolean isSelect = sqlCommandType == SqlCommandType.SELECT;

    //构造MappedStatement
    MappedStatement.Builder statementBuilder = new MappedStatement.Builder(configuration, id, sqlSource, sqlCommandType)
        .resource(resource)
        .fetchSize(fetchSize)
        .timeout(timeout)
        .statementType(statementType)
        .keyGenerator(keyGenerator)
        .keyProperty(keyProperty)
        .keyColumn(keyColumn)
        .databaseId(databaseId)
        .lang(lang)
        .resultOrdered(resultOrdered)
        .resultSets(resultSets)
        .resultMaps(getStatementResultMaps(resultMap, resultType, id))
        .resultSetType(resultSetType)
        .flushCacheRequired(valueOrDefault(flushCache, !isSelect))
        .useCache(valueOrDefault(useCache, isSelect))
        .cache(currentCache);

    ParameterMap statementParameterMap = getStatementParameterMap(parameterMap, parameterType, id);
    if (statementParameterMap != null) {
      statementBuilder.parameterMap(statementParameterMap);
    }

    MappedStatement statement = statementBuilder.build();
	// 向configuration添加MappedStatement
    configuration.addMappedStatement(statement);
    return statement;
  }
  
 } 
总体流程

1:spring boot 启动,加载MybatisPlusAutoConfiguration.java类,初始化SqlSessionFactory,

2:MybatisSqlSessionFactoryBean调用MybatisSqlSessionFactoryBean.java的getObject()方法,进而调用this.afterPropertiesSet()方法

3:调用buildSqlSessionFactory()方法获取项目配置的所有mybatis xml文件,通过xmlMapperBuilder.parse()方法循环解析xml

4:调用buildStatementFromContext(context.evalNodes("select|insert|update|delete"))方法解析sql节点

5:调用parseStatementNode() 方法获取xml里面的具体sql信息

6:调用builderAssistant.addMappedStatement方法进行封装MappedStatement对象,最后调用configuration.addMappedStatement(statement)放入到configuration里

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/843284.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号