Mybatis源码的理解

news2024/11/25 12:03:24

文章目录

  • 0.核心的包
    • 1.1 配置文件mybatis-config.xml
    • 1.2 配置文件解析
      • 将配置文件转化为输入流,将 xml转化Configuration类.
      • 解析配置对应的标签为Configuration的属性
      • Configuration的核心类的属性
    • 1.3 解析完成查询之后的configuration
      • environment类
      • sqlFragments类
      • mapperRegistry类
      • mapperStatements
      • caches类
  • 2.SQL解析
    • 2.1 XMLMapperBuilder
      • 属性
      • 解析文件的mapper的命名空间,缓存,参数,结果集以及sql.
      • 解析参数parameterMap
      • 解析sql片段
    • 2.2 MapperAnnotationBuilder
  • 3. SQL执行:
    • 3.1 获取SqlSession 以及获取执行器
    • 3.2 Executor【SimpleExecutor ReuseExecutor】
      • executorType类型
      • 根据类型获取执行器
      • 执行sql语句
      • 从配置文件拿到执行的语句
      • jdbc执行
  • 4. 结果映射:ResultSetHandler
    • 4.1 执行拿到返回结果进行处理
      • 执行返回的数据
    • 4.2 resultSetHandler.handleResultSets(ps)

0.核心的包

在这里插入图片描述# 1.Configuration类

1.1 配置文件mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <!---导入配置文件-->
    <properties resource="db.properties"></properties>
 
    <settings>
        <!--设置日志实现-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
        <!--开启二级缓存-->
        <setting name="cacheEnabled" value="true"/>
    </settings>
    
    <environments default="development">
        <environment id="development">
              <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="mapper/PersonMapper.xml"/>
    </mappers>
</configuration>

1.2 配置文件解析

将配置文件转化为输入流,最终将 xml转化Configuration类.

将配置文件转化为输入流,将 xml转化Configuration类.

//XMLConfigBuilder  解析器
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
//将xml转化为Document
public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
    commonConstructor(validation, variables, entityResolver);
    this.document = createDocument(new InputSource(inputStream));
}

解析配置对应的标签为Configuration的属性

 private void parseConfiguration(XNode root) {
    try {
      // issue #117 read properties first
      propertiesElement(root.evalNode("properties"));
      Properties settings = settingsAsProperties(root.evalNode("settings"));
      loadCustomVfs(settings);
      loadCustomLogImpl(settings);
      typeAliasesElement(root.evalNode("typeAliases"));
      pluginElement(root.evalNode("plugins"));
      objectFactoryElement(root.evalNode("objectFactory"));
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      reflectorFactoryElement(root.evalNode("reflectorFactory"));
      settingsElement(settings);
      // read it after objectFactory and objectWrapperFactory issue #631
      environmentsElement(root.evalNode("environments"));
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      typeHandlerElement(root.evalNode("typeHandlers"));
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }

Configuration的核心类的属性

public class Configuration {
  //加载环境
  protected Environment environment;
  //是否开启缓存
  protected boolean cacheEnabled = true;
  //配置日志的实现
  protected Class<? extends Log> logImpl;
  //配置属性Properties 
  protected Properties variables = new Properties();
  protected ObjectFactory objectFactory = new DefaultObjectFactory();
  protected ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();
  ///代理工厂 
  protected ProxyFactory proxyFactory = new JavassistProxyFactory();
  //数据库ID
  protected String databaseId;
  //mapper注册
  protected final MapperRegistry mapperRegistry = new MapperRegistry(this);
  //拦截器注册类
  protected final InterceptorChain interceptorChain = new InterceptorChain();
  //类型处理器
  protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry(this);
  //类别名注册
  protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();
//加载映射的mapper xml
  protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>(
      "Mapped Statements collection")
          .conflictMessageProducer((savedValue, targetValue) -> ". please check " + savedValue.getResource() + " and "
              + targetValue.getResource());
 //加载的缓存
  protected final Map<String, Cache> caches = new StrictMap<>("Caches collection");
  //xml结果集
  protected final Map<String, ResultMap> resultMaps = new StrictMap<>("Result Maps collection");
  //参数的
  protected final Map<String, ParameterMap> parameterMaps = new StrictMap<>("Parameter Maps collection");
  //主键生成器 
  protected final Map<String, KeyGenerator> keyGenerators = new StrictMap<>("Key Generators collection");
  ///sql片段
  protected final Map<String, XNode> sqlFragments = new StrictMap<>("XML fragments parsed from previous mappers");


  public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject,
      BoundSql boundSql) {
    ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement,
        parameterObject, boundSql);
    return (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
  }
// ResultSetHandler  结果集处理
  public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds,
      ParameterHandler parameterHandler, ResultHandler resultHandler, BoundSql boundSql) {
    ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler,
        resultHandler, boundSql, rowBounds);
    return (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
  }

  public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement,
      Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject,
        rowBounds, resultHandler, boundSql);
    return (StatementHandler) interceptorChain.pluginAll(statementHandler);
  }

  public Executor newExecutor(Transaction transaction) {
    return newExecutor(transaction, defaultExecutorType);
  }
  //获取执行器
  public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    executorType = executorType == null ? defaultExecutorType : executorType;
    Executor executor;
    if (ExecutorType.BATCH == executorType) {
      executor = new BatchExecutor(this, transaction);
    } else if (ExecutorType.REUSE == executorType) {
      executor = new ReuseExecutor(this, transaction);
    } else {
      executor = new SimpleExecutor(this, transaction);
    }
    if (cacheEnabled) {
      executor = new CachingExecutor(executor);
    }
    return (Executor) interceptorChain.pluginAll(executor);
  }

  //获取注册mapper类
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
  }
}

1.3 解析完成查询之后的configuration

public Configuration parse() {
    if (parsed) {
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    parsed = true;
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
  }

environment类

环境类

sqlFragments类

sqlFragments

mapperRegistry类

mapperRegistry

mapperStatements

mappedStatements

caches类

resultMaps

2.SQL解析

sql的解析有两种,一个是标签注解,一个是xml配置文件的解析。对应的映射解析器为XMLMapperBuilder和MapperAnnotationBuilder

2.1 XMLMapperBuilder

属性

 private final XPathParser parser;
 //辅助构建类
 private final MapperBuilderAssistant builderAssistant;
 //加载的sql片段
 private final Map<String, XNode> sqlFragments;
 private final String resource;

解析文件的mapper的命名空间,缓存,参数,结果集以及sql.

private void configurationElement(XNode context) {
    try {
      String namespace = context.getStringAttribute("namespace");
      if (namespace == null || namespace.isEmpty()) {
        throw new BuilderException("Mapper's namespace cannot be empty");
      }
      builderAssistant.setCurrentNamespace(namespace);
      cacheRefElement(context.evalNode("cache-ref"));
      cacheElement(context.evalNode("cache"));
      parameterMapElement(context.evalNodes("/mapper/parameterMap"));
      resultMapElements(context.evalNodes("/mapper/resultMap"));
      sqlElement(context.evalNodes("/mapper/sql"));
      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);
    }
  }

解析参数parameterMap

private void parameterMapElement(List<XNode> list) {
    for (XNode parameterMapNode : list) {
      String id = parameterMapNode.getStringAttribute("id");
      String type = parameterMapNode.getStringAttribute("type");
      Class<?> parameterClass = resolveClass(type);
      List<XNode> parameterNodes = parameterMapNode.evalNodes("parameter");
      List<ParameterMapping> parameterMappings = new ArrayList<>();
      for (XNode parameterNode : parameterNodes) {
        String property = parameterNode.getStringAttribute("property");
        String javaType = parameterNode.getStringAttribute("javaType");
        String jdbcType = parameterNode.getStringAttribute("jdbcType");
        String resultMap = parameterNode.getStringAttribute("resultMap");
        String mode = parameterNode.getStringAttribute("mode");
        String typeHandler = parameterNode.getStringAttribute("typeHandler");
        Integer numericScale = parameterNode.getIntAttribute("numericScale");
        ParameterMode modeEnum = resolveParameterMode(mode);
        Class<?> javaTypeClass = resolveClass(javaType);
        JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
        Class<? extends TypeHandler<?>> typeHandlerClass = resolveClass(typeHandler);
        ParameterMapping parameterMapping = builderAssistant.buildParameterMapping(parameterClass, property, javaTypeClass, jdbcTypeEnum, resultMap, modeEnum, typeHandlerClass, numericScale);
        parameterMappings.add(parameterMapping);
      }
      builderAssistant.addParameterMap(id, parameterClass, parameterMappings);
    }

解析sql片段

sqlfragment

2.2 MapperAnnotationBuilder

3. SQL执行:

3.1 获取SqlSession 以及获取执行器

 private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level,
      boolean autoCommit) {
    Transaction tx = null;
    try {
      final Environment environment = configuration.getEnvironment();
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      final Executor executor = configuration.newExecutor(tx, execType);
      return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
      closeTransaction(tx); // may have fetched a connection so lets call close()
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

3.2 Executor【SimpleExecutor ReuseExecutor】

接口–》Executor --》 SimpleExecutor ReuseExecutor 【Statement–JDBC】

executorType类型

public enum ExecutorType {
  SIMPLE,
  REUSE,
  BATCH
}

根据类型获取执行器

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    executorType = executorType == null ? defaultExecutorType : executorType;
    Executor executor;
    if (ExecutorType.BATCH == executorType) {
      executor = new BatchExecutor(this, transaction);
    } else if (ExecutorType.REUSE == executorType) {
      executor = new ReuseExecutor(this, transaction);
    } else {
      executor = new SimpleExecutor(this, transaction);
    }
    if (cacheEnabled) {
      executor = new CachingExecutor(executor);
    }
    return (Executor) interceptorChain.pluginAll(executor);
  }

执行sql语句

执行

从配置文件拿到执行的语句

  private <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
    try {
      MappedStatement ms = configuration.getMappedStatement(statement);
      dirty |= ms.isDirtySelect();
      return executor.query(ms, wrapCollection(parameter), rowBounds, handler);
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

执行器

绑定sql

  public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds,
      ResultHandler resultHandler, BoundSql boundSql) {

    switch (ms.getStatementType()) {
      case STATEMENT:
        delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case PREPARED:
        delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case CALLABLE:
        delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      default:
        throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
    }

  }

jdbc执行

在这里插入图片描述

mysql执行

4. 结果映射:ResultSetHandler

4.1 执行拿到返回结果进行处理

  @Override
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();
    return resultSetHandler.handleResultSets(ps);
  }

执行返回的数据

最终返回的

4.2 resultSetHandler.handleResultSets(ps)

结果处理

 public List<Object> handleResultSets(Statement stmt) throws SQLException {
    ErrorContext.instance().activity("handling results").object(mappedStatement.getId());

    final List<Object> multipleResults = new ArrayList<>();

    int resultSetCount = 0;
    ResultSetWrapper rsw = getFirstResultSet(stmt);

    List<ResultMap> resultMaps = mappedStatement.getResultMaps();
    int resultMapCount = resultMaps.size();
    validateResultMapsCount(rsw, resultMapCount);
    while (rsw != null && resultMapCount > resultSetCount) {
      ResultMap resultMap = resultMaps.get(resultSetCount);
      handleResultSet(rsw, resultMap, multipleResults, null);
      rsw = getNextResultSet(stmt);
      cleanUpAfterHandlingResultSet();
      resultSetCount++;
    }

    String[] resultSets = mappedStatement.getResultSets();
    if (resultSets != null) {
      while (rsw != null && resultSetCount < resultSets.length) {
        ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
        if (parentMapping != null) {
          String nestedResultMapId = parentMapping.getNestedResultMapId();
          ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
          handleResultSet(rsw, resultMap, null, parentMapping);
        }
        rsw = getNextResultSet(stmt);
        cleanUpAfterHandlingResultSet();
        resultSetCount++;
      }
    }

    return collapseSingleResultList(multipleResults);
  }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/575690.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

(转载)基于量子遗传算法的函数寻优算法

8.1 理论基础 8.1.1 量子遗传算法概述 量子遗传算法(quantum genetic algorithm,QGA)是量子计算与遗传算法相结合的产物&#xff0c;是一种新发展起来的概率进化算法。遗传算法是处理复杂优化问题的一种方法&#xff0c;其基本思想是模拟生物进化的优胜劣汰规则与染色体的交…

结构型设计模式02-代理模式

✨作者&#xff1a;猫十二懿 ❤️‍&#x1f525;账号&#xff1a;CSDN 、掘金 、个人博客 、Github &#x1f389;公众号&#xff1a;猫十二懿 代理模式 1、不使用代理模式 举例说明&#xff1a;小明喜欢一个女生&#xff08;小红&#xff09;&#xff0c;因为小红不认识小明…

【数据结构】初步了解排序

Yan-英杰的主页 悟已往之不谏 知来者之可追 C程序员&#xff0c;2024届电子信息研究生 目录 1.排序的概念及其运用 1.1排序的概念 2.常见排序算法的实现 2.1插入排序 2.2希尔排序 问题:gap是多少合适&#xff1f; 1.排序的概念及其运用 1.1排序的概念 排序&#xff1a;所…

App上架流程

准备 开发者账号完工的项目 上架步骤 一、创建App ID二、创建证书请求文件 &#xff08;CSR文件&#xff09;三、创建发布证书 &#xff08;CER&#xff09;四、创建Provisioning Profiles配置文件 &#xff08;PP文件&#xff09;五、在App Store创建应用六、打包上架 一、…

设置linux的时间

目录 一、什么是时间 &#xff08;1&#xff09;例子1 &#xff08;2&#xff09;例子2 二、什么是本地时间 三、linux设置本地时间的方法 &#xff08;1&#xff09;方式一&#xff1a;通过互联网自动同步 1.修改时间同步服务器 2.查看时间同步情况 &#xff08;2&…

自动化测试1

目录 1.什么是自动化测试 1.1自动化分类 1.1单元测试 1.2接口测试 1.3UI自动化测试 2.selenium 1.什么是selenium 2.selenium的特点 3.工作原理 3.seleniumJava 1.搭建 1.查看Chrome版本 2.下载Chrome浏览器驱动 3.配置,放到该目录下 2.验证是否搭建成功 1.什么是…

springboot 集成jwt的使用

1.JWT介绍 JWT&#xff08;JSON Web Token&#xff09;是一种基于JSON格式的身份验证和授权标准&#xff0c;经常用于Web应用程序中的用户身份验证。JWT由三个部分组成&#xff1a;头部、载荷和签名。头部包含算法和类型信息&#xff0c;载荷包含用户数据和元数据&#xff0c;…

tolua源码分析(六) C#委托使用lua函数的机制实现

tolua源码分析&#xff08;六&#xff09; C#委托使用lua函数的机制实现 上一节我们讨论lua层如何使用C#的enum以及使用enum需要注意的事项。这一节我们将讨论项目日常开发中经常会用到的委托注册机制&#xff0c;即C#层暴露若干委托和事件&#xff0c;然后在lua层进行注册&…

【沐风老师】3DMAX宇宙生成器(一键生成星系)插件使用方法详解

3DMAX宇宙生成器&#xff08;一键生成星系&#xff09;插件 3DMAX宇宙生成器&#xff08;一键生成星系&#xff09;插件&#xff0c;用于模拟星团及星系的运动。可以创建单个集合进行动画计算&#xff0c;也可以输入不同坐标&#xff0c;建立多个集合后统一进行动画计算。 【安…

探索iOS之CoreImage框架

CoreImage提供图像处理、人脸识别、图像增强、图像滤镜、图像转场。它操作的数据来自Core Graphics、Core Video、Image IO&#xff0c;使用CPU或GPU进行渲染。CoreImage对底层实现进行封装&#xff0c;为上层提供简单易用的API。 一、CoreImage框架 CoreImage框架分为&#…

计算机电脑中了勒索病毒,如何提高windows系统预防faust勒索病毒的能力

当今社会互联网技术迅猛发展&#xff0c;但随之而来的网络安全问题开始引起人们的重视&#xff0c;其中,勒索软件是当前网络安全领域中最具破坏性和危害性的恶意软件之一&#xff0c;而Faust勒索软件就是其中一种。 Faust勒索病毒是一种很可怕的恶意软件&#xff0c;能够破坏并…

计算机网络 - 网络层的数据平面

Overview 首先Network Layer负责的是host to host的传输, 然后可以分为两个平面, 控制平面以及数据平面. 数据平面: 负责forward datagrams from input to output links 决定路由器从input到output 转发功能: 基于目标地址 转发表 SDN方式基于多个字段流表 控制平面: 调…

第10届蓝桥杯Scratch省赛真题集锦

编程题 第 1 题 问答题 击鼓游戏 题目说明 准备工作: 将复台背景设置为“spotight-stage”&#xff0c;添加一个“Belerina"角色、两个“Drum1"角色和两个“Drum2”角色&#xff0c;并按照图 7-1 的位置摆放。角色“Beleina"的造型和颜色的设置须如图 7-1所示&a…

美女放电还是整形-从《人月神话》误译谈状态机图

DDD领域驱动设计批评文集 欢迎加入“软件方法建模师”群 《软件方法》各章合集 在重审《人月神话》中译本的过程中&#xff0c;发现一处较严重的误译。 原文是&#xff1a; the first milepost is not reached until two months have elapsed. 原译为&#xff1a; 两个月…

Java中常量基础知识

1 问题 什么是字面常量&#xff1f; 2 方法 拿第一行输出语句来说&#xff0c;这行代码输出了 “hello” 这个字符串&#xff0c;无论何时何地运行程序&#xff0c;输出的这个字符串都不会变&#xff0c;这就是字面常量。 定义&#xff1a;常量即程序运行期间&#xff0c;固定不…

chatgpt网站优选集合

目录 chatGpt 国内镜像网站集合 chatgpt接入微信 chatgpt接入谷歌浏览器 chatgptAI绘画 最后 chatGpt 这个说实话&#xff0c;不用我介绍大家也都懂。不如玩一个有意思的&#xff0c;这里我让chatGpt自己介绍一下他自己&#xff1a; 嗨&#xff0c;大家好&#xff0c;我是…

C++ [STL之vector模拟实现]

本文已收录至《C语言和高级数据结构》专栏&#xff01; 作者&#xff1a;ARMCSKGT STL之vector模拟实现 前言正文空间结构默认成员函数构造函数拷贝构造函数赋值重载析构函数关于数据拷贝问题 迭代器容量操作查询容量容量操作 数据访问下标访问头尾数据访问 数据增删尾插尾删重…

学懂缓存雪崩,缓存击穿,缓存穿透仅需一篇,基于Redis讲解

在了解缓存雪崩、击穿、穿透这三个问题前&#xff0c;我们需要知道为什么我们需要缓存。在了解这三个问题后&#xff0c;我们也必须知道使用Redis时&#xff0c;如何解决这些问题。 所以我将按照"为什么我们需要缓存"、"什么是缓存雪崩、击穿、穿透"、&qu…

Linux学习笔记 --- Linux基础命令Part1

一. Linux的目录结构 目标&#xff1a;1. 掌握Linux系统的目录结构 2. 掌握Linux系统的路径表达形式 1.1 Linux系统的目录结构 我们知道&#xff0c;在操作系统中&#xff0c;文件系统的目录结构一般都是树形结构。Linux的目录结构是一个树型结构Windows 系统可以拥有多…

如何使用wireShark抓取还原文件

简介 WireShark的追踪流功能可以帮我们抓取从网络上下载的各种文件&#xff0c;接下来就演示下如何抓取并且进行还原。 使用Nginx搭建文件存储服务器 只要是通过http网站下载的包&#xff0c;都可以通过追踪流工具进行抓取。这里为了演示&#xff0c;临时搭建一个Nginx文件存…