IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> Mybatis MappedStatement原理 -> 正文阅读

[大数据]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<ResultMap> 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<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {

  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文件 比如: 项目路径\target\classes\mapper\SelectUserMapper.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<XNode> 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里

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2022-04-28 11:56:15  更:2022-04-28 11:57:33 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 1:31:39-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码