Mybatis之SqlSessionFactoryBean源码初步解析(一)

SpringBoot:注入多个SqlSessionFactoryBean实现不同的数据库访问(iotdb和mysql) 1. 声明 当前内容主要为复习在spring中注入多个sqlSessionFactoryBean来访问不同的数据库的操作 主要为: 注入mysql的sqlSessionFactoryBean 注入iotdb的sqlSessionFactoryBean 实现数据访问操作 pom依赖 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter- 阅读详情

首先先道歉一下, 我之前并没有研究太深入,然后发现有些东西写错了。然后7月7 号,忙到夜里2点改这篇文章。改完之后太累了就关了电脑。。。然后没保存发布,又重写了一遍。

第二篇的地址

Mybatis 的两个入口一个是SqlSessionFactoryBean, 另外一个是MapperScannerConfigurer。这个可以在spring.xml 配置中找到。SqlSessionFactoryBean实现了InitializingBean接口,InitializingBean接口必须得实现afterpropertiesset()方法,此方法将配置文件中的各种属性列如 mapperlocation 、typealias、plugins等等放入configuration中,configuration就相当于mybatis的大管家, 各种解析封装后的属性都会放到这里。 然后您会看到

else if (this.configLocation != null) {
      xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);
      configuration = xmlConfigBuilder.getConfiguration();
    

xmlConfigBuilder这个东西是解析xml 的一个类 

 xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);
这里就是装配配置文件
if (xmlConfigBuilder != null) {
      try {
        xmlConfigBuilder.parse();

        if (LOGGER.isDebugEnabled()) {
          LOGGER.debug("Parsed configuration file: '" + this.configLocation + "'");
        }
      } catch (Exception ex) {
        throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex);
      } finally {
        ErrorContext.instance().reset();
      }
    }
继续往下运行的时候会发现
xmlConfigBuilder.parse();
这个就是开始解析xml了 这边是专门解析下图中configLocation 对应的xml
<configuration>
 <!-- 全局的setting配置 根据需要添加  需要二级缓存 延迟加载 就可以配置-->


 <!-- 配置别名 -->
   <typeAliases>
      <!-- 批量扫描别名 -->
       <package name="com.fuchanghai.mybatis.pojo"/>
        <!--<package name="cn.zx.ssm.po"/>  -->
   </typeAliases>
<!-- 使用自动扫描器时,mapper.xml文件如果和mapper.java接口在一个目录则此处不用定义mappers 
   -->
 <mappers>
      <package name="com.fuchanghai.mybatis.mapper" />
   </mappers>  
</configuration>

这个xml 里面的最外层标签是configuration;所以下面最先解析的是configuration

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

  private void parseConfiguration(XNode root) {
    try {
      //issue #117 read properties first
      propertiesElement(root.evalNode("properties"));
      Properties settings = settingsAsProperties(root.evalNode("settings"));
      loadCustomVfs(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标签的话就开始解析了。然后我们主讲一下mappers 标签。
 mapperElement(root.evalNode("mappers"));

这句话就是解析mappers的子元素了

如果子元素是package 那么调用configuration的addMappers()将包路径扔给configuration.

如果mappers标签的子元素标签不是package 。那么得到他子元素3个属性的值,分别是resource、url、class 。三者只能同时存在一个。同时存在多以一个则报异常。因为configuration.addMappers()方法最终也是调到XMLMapperBuilder.

configuration.addMappers() 里面是调用mapperRegistry.addMappers()。 

 private void mapperElement(XNode parent) throws Exception {
    if (parent != null) {
      for (XNode child : parent.getChildren()) {
        if ("package".equals(child.getName())) {
          String mapperPackage = child.getStringAttribute("name");
          configuration.addMappers(mapperPackage);
        } else {
          String resource = child.getStringAttribute("resource");
          String url = child.getStringAttribute("url");
          String mapperClass = child.getStringAttribute("class");
          if (resource != null && url == null && mapperClass == null) {
            ErrorContext.instance().resource(resource);
            InputStream inputStream = Resources.getResourceAsStream(resource);
            XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
            mapperParser.parse();
          } else if (resource == null && url != null && mapperClass == null) {
            ErrorContext.instance().resource(url);
            InputStream inputStream = Resources.getUrlAsStream(url);
            XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
            mapperParser.parse();
          } else if (resource == null && url == null && mapperClass != null) {
            Class<?> mapperInterface = Resources.classForName(mapperClass);
            configuration.addMapper(mapperInterface);
          } else {
            throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
          }
        }
      }
    }
  }

我对于mapperRegistry是哪里来的 很感兴趣。于是我看到了下面代码所示

  protected MapperRegistry mapperRegistry = new MapperRegistry(this);
public void addMappers(String packageName) {
    mapperRegistry.addMappers(packageName);
  }

这里的this 代表的就是Configuration这个类。

进入mapperRegistry.addMappers() 方法会进入下图。 先调用下面代码中最后一个方法, 再调用上一个方法。

public void addMappers(String packageName, Class<?> superType) {
    ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();
    resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
    Set<Class<? extends Class<?>>> mapperSet = resolverUtil.getClasses();
    for (Class<?> mapperClass : mapperSet) {
      addMapper(mapperClass);
    }
  }

  /**
   * @since 3.2.2
   */
  public void addMappers(String packageName) {
    addMappers(packageName, Object.class);
  }

这边再道个歉。 先不上图了,本来有图的 我忘了保存。 我就嘴说说吧

这边的mapperSet 呢解析出来是什么格式呢:

[interface com.fuchanghai.mybatis.mapper.DailyMapper, interface com.fuchanghai.mybatis.mapper.EmployeeMapper]

意思就是interface+全路径。 很有意思的是:比如我这样配置的

<package name="com.fuchanghai.mybatis.mapper" />
那么只会解析com.fuchanghai.mybatis.mapper下的。 如果你的xml放在com.fuchanghai.mybatis.mapper.test。这个包下, 那么是不会在mapperSet中的。注意看图下的size.



我们继续看调到addMapper()方法:

 public <T> void addMapper(Class<T> type) {
    if (type.isInterface()) {
      if (hasMapper(type)) {
        throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
      }
      boolean loadCompleted = false;
      try {
        knownMappers.put(type, new MapperProxyFactory<T>(type));
        // It's important that the type is added before the parser is run
        // otherwise the binding may automatically be attempted by the
        // mapper parser. If the type is already known, it won't try.
        MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
        parser.parse();
        loadCompleted = true;
      } finally {
        if (!loadCompleted) {
          knownMappers.remove(type);
        }
      }
    }
  }

hasMapper(type)方法调用的是什么呢?看下面代码

public <T> boolean hasMapper(Class<T> type) {
    return knownMappers.containsKey(type);
  }

意思就是看看knownMappers 里面有没有,即是缓存里面存在不存在。knownMappers 这个属性很重要 再之后的代码中会出现正到。

如果没有的话就存到knownMappers 中

这个 newMapperProxyFactory()重中之重 干了什么 呢? 没错动态代理, 掉个胃口,下次再说。

然后要看MapperAnnotationBuild这个方法了。

type传进去只为了再后面拼接一个.java 然后赋值给resource属性

我们主要看parse.parse();

下面代码 中主要的是loadXmlResource(), 和parseStatement(method);


 public void parse() {
    String resource = type.toString();
    if (!configuration.isResourceLoaded(resource)) {
      loadXmlResource();
      configuration.addLoadedResource(resource);
      assistant.setCurrentNamespace(type.getName());
      parseCache();
      parseCacheRef();
      Method[] methods = type.getMethods();
      for (Method method : methods) {
        try {
          // issue #237
          if (!method.isBridge()) {
            parseStatement(method);
          }
        } catch (IncompleteElementException e) {
          configuration.addIncompleteMethod(new MethodResolver(this, method));
        }
      }
    }
    parsePendingMethods();
  }

loadXmlResource()就是解析xml 文件了 最终调用了xmlMapperBuilder。 这里的!configuration.isResourceLoaded("namespace:" + type.getName())也很有深意的。各位试试debug 看看。

private void loadXmlResource() {
    // Spring may not know the real resource name so we check a flag
    // to prevent loading again a resource twice
    // this flag is set at XMLMapperBuilder#bindMapperForNamespace
    if (!configuration.isResourceLoaded("namespace:" + type.getName())) {
      String xmlResource = type.getName().replace('.', '/') + ".xml";
      InputStream inputStream = null;
      try {
        inputStream = Resources.getResourceAsStream(type.getClassLoader(), xmlResource);
      } catch (IOException e) {
        // ignore, resource is not required
      }
      if (inputStream != null) {
        XMLMapperBuilder xmlParser = new XMLMapperBuilder(inputStream, assistant.getConfiguration(), xmlResource, configuration.getSqlFragments(), type.getName());
        xmlParser.parse();
      }
    }
  }

这个是运用反射渠道对应的接口类放到大管家里面(configuration):

 Class<?> mapperInterface = Resources.classForName(mapperClass);
            configuration.addMapper(mapperInterface);

  XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
            mapperParser.parse();

这边就是解析mapper标签。继续点进去是这样的:

 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);
      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. Cause: " + e, e);
    }
  }

 private void buildStatementFromContext(List<XNode> list) {
    if (configuration.getDatabaseId() != null) {
      buildStatementFromContext(list, configuration.getDatabaseId());
    }
    buildStatementFromContext(list, null);
  }

  private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
    for (XNode context : list) {
      final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
      try {
        statementParser.parseStatementNode();
      } catch (IncompleteElementException e) {
        configuration.addIncompleteStatement(statementParser);
      }
    }
  }
上图一定会进入
 buildStatementFromContext(List<XNode> list)

这个方法是得到 select|updata等等东西的contant。

然后进

buildStatementFromContext(List<XNode> list, String requiredDatabaseId)
requiredDatabaseId这个配置的是musql 或者oracle 判断是哪个数据库源

statementParser.parseStatementNode();

这个里面进去找找到langDriver.createSqlSource 然后继续找builder.parseScriptNode(), 进去继续找 List<SqlNode> contents = parseDynamicTags(context);。 这个是个递归的方法,然后就是sqlnode staticsqlnode dynamicsqlnode sqlsource之前的封装,不去细说了。


至于为什么 mapper接口 明明是一个接口怎么 能进行动态代理这个问提。 我不想一步步跟了,简单的说一下就是在mapperlocation那边进去找到MapperRegistry。

最后可以看到

 public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }


[2021-10-18] MyBatis-plus项目打包遇到的问题记录,sqlSessionFactory配置 MyBatis-plus打包遇到问题记录 我的项目是Spring Boot整合了MyBatis-plus,maven引入如下 <!-- 持久层框架 mybatis-plus --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> 阅读详情

相关推荐

Spring整合MyBatis之SqlSessionFactory对象的产生

目录为什么 `MyBatis` 要和 `Spring` 整合`Spring` 整合 `MyBatis``Maven` 依赖创建 `Spring` 配置文件 为什么 MyBatis 要和 Spring 整合 Spring 会帮助我们管理 bean:省去我们对 SqlSessionFactory、SqlSession、Mapper 这些核心对象(bean)的创建,不需要我们手工去创建了,Spring 会通过 IOC 容器来帮我们管理这些对象 Spring 使用 xxxTemplate 封装了方法:Spring

桐花思雨 2458

MyBatis入门系列(22) -MyBatis-Spring核心源码解析之SqlSessionFactoryBean

前言 在之前使用了mybatis的文档中,我们需要手动创建SqlSessionFactory对象来获取SqlSession,然后通过SqlSession获取mapper代理对象,进行数据库操作。 // 根据xml配置文件(全局配置文件)创建一个SqlSessionFactory对象 String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); Sql

记录知识、锤炼自我 5785

Mybatis源码解析之Spring集成mybatis-spring分析

Mybatis源码解析之核心类分析 Mybatis源码解析之初始化分析 Mybatis源码解析之执行流程解析 Mybatis源码解析之数据库连接和连接池 Mybatis源码解析之事务管理 Mybatis源码解析之缓存机制(一):一级缓存 Mybatis源码解析之缓存机制(二):二级缓存 Mybatis源码解析之插件机制 前面的几篇相关博客都针对原生的mybatis进行解析,从本文开始将针对myba...

翻身已碰头的博客 1211

Spring-MyBatis 之 SqlSessionFactoryBean

在基本的 MyBatis 中,session 工厂可以使用 SqlSessionFactoryBuilder 来创建。而在 MyBatis-Spring 中,则使用 SqlSessionFactoryBean 来替代。 Spring 的 XML 配置文件:       SqlSessionFactoryBean这个类实现了三个接口,一个是InitializingBean,

zsg88的专栏 1984

深入 MyBatis-Spring 源码解析 ——揭秘 MyBatis 与 Spring 的完美融合

当谈到 Java 的持久层框架,MyBatis 几乎总会出现在讨论中;它轻量、灵活,非常适合需要复杂 SQL 查询的场景。而我们的大管家 Spring,除了帮我们管理依赖和控制反转之外,还可以跟 MyBatis 完美地配合在一起!这就是我们今天要讨论的主题——。在这个分析中,我们将通过源码来揭秘 MyBatis-Spring 是如何在两者间架起桥梁的,希望让你对其工作原理有一个深入的理解。MyBatis-Spring 是 Spring 提供的一个适配器模块,它的目标是帮助开发者在 Spring 应用中。

喵手的博客 2022

从工创赛实战到开源:一个高鲁棒性智能物流视觉系统的构建与优化

本文分享了从工创赛实战中构建高鲁棒性智能物流视觉系统的完整经验。针对赛场复杂光线环境,详细阐述了摄像头选型、基于CLAHE和形态学梯度的抗干扰色环识别算法、卡尔曼滤波状态估计以及多线程串口通讯与任务调度等核心优化策略,旨在打造一个稳定可靠的视觉系统,并已将相关代码开源。

weixin_29046035的博客 320

Mybatis之SqlSessionFactoryBean源码初步解析(二)主写怎么解析resultMap以及查询语句

这边文章接Mybatis之SqlSessionFactoryBean源码初步解析(一)。 直接进入主题 private void configurationElement(XNode context) { try { String namespace = co...

120

人机协作新纪元:AI会抢走IT人的饭碗吗?

产品经理用自然语言描述需求,AI将其转化为技术规格书(准确率已达89%)

819

Mybatis之SqlSessionFactoryBean源码初步解析(三)mapper的动态代理

见鬼,这个csdn 有bug 吧, 粘贴复制然后卡死,gg归零了解一下 sql的动态代理(反推) 我跟着第二篇后面继续写,在第二篇的时候我们提到了knowMappers代码如下: if (type.isInterface()) { if (hasMapp...

177

微带线,带状线和接地共面波导的区别

微带线,带状线和接地共面波导的区别

sky_ying的博客 3万+

如何修复Windows卡在“正在准备Windows”的问题?这里有详细步骤

如何修复Windows卡在“正在准备Windows”的问题?这里有详细步骤。

wyxtx的博客 5664

Spring源码解析(十):spring整合mybatis源码

通过sqlSession获取对应的代理对象代理对象执行sql完成数据库操作// 1.解析XML配置// 2.基于解析好的XML配置创建一个SqlSessionFactory// 3.通过SqlSessionFactory,创建一个SqlSession// 4.获取一个代理对象// 5.调用代理对象的方法System.out.println("代理对象查询结果:" + mapper.selectOne(1));根据@MapperScan注解扫描指定路径下接口。

从基础到源码解析的学习记录 1275

不止于连接:用VS Code Remote-SSH深度开发树莓派(Ubuntu 22.04环境实战)

本文详细介绍了如何在Ubuntu 22.04环境下使用VS Code的Remote-SSH功能进行树莓派深度开发。通过SSH配置、VS Code扩展安装和远程环境优化,开发者可以在本地高效编写代码,同时在树莓派上直接运行和测试,解决性能瓶颈问题。文章还提供了高级功能如端口转发、多项目管理和远程调试的实战技巧。

didui8202的博客 352

mybatis与spring的整合之SqlSessionFactoryBean

mybatis与spring的整合之SqlSessionFactoryBeanSqlSessionFactoryBean配置注入mapperLocations注入configLocationmapperLocations与configLocation比较SqlSessionFactoryBean源码跟踪实现了FactoryBean接口实现了InitializingBean接口dataSource不...

yu_kang的博客 4万+

Modelsim:LPDDR5仿真(含美光仿真模型官方sv&vcs代码)

虽然,三星在设计跟量产上,早于其他家存储产商,但是镁光后来居上了,是业界首家支持全速 LPDDR5 的供应商,并且开发者在做开发的时候,也是用美光颗粒比较多,所以这里就先以美光的仿真模型为主进行仿真。 本工程为美光官方工程,支持Modelsim、VCS、ncverilog三种仿真器仿真。模型破解过,为完整system-verilog代码。

千歌叹尽执夏的博客 1283

【嘉立创EDA】从AD21导入pcb边界到嘉立创EDA专业版

有许多前期工程由AD进行完成,在后续update的过程中,由于开模等原因限制,部分pcb外型需要继续沿用,本文将此过程记录,以供有需要的读者参考。

l64481000的博客 4520

MyBatis与Spring集成原理:SqlSessionFactoryBean源码分析

作为Java开发中最流行的持久层框架之一,MyBatis与Spring的完美集成是其成功的关键因素。本文将通过深入分析SqlSessionFactoryBean的源码实现,揭示MyBatis与Spring集成的核心原理,帮助开发者更好地理解和使用这一强大的技术组合。 ## 什么是SqlSessionFactoryBean? **SqlSessionFactoryBean**是MyBatis-S

gitblog_00388的博客 814

深入介绍 SAP OData CSRF Token 的一些技术细节

跨站请求伪造(Cross-Site Request Forgery,简称 CSRF)是一种网络攻击手段,它允许攻击者伪造用户的身份来执行未经授权的操作。为了防止 CSRF 攻击,常用的一种技术手段就是 CSRF Token.CSRF Token 是一种随机生成的防伪 Token,它由服务器颁发给客户端,并需要客户端在提交某些特定类型的请求时,将该 Token 添加到 HTTP 请求的头部字段去。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 643

MyBatis-Spring核心源码解析之SqlSessionFactoryBean+BasicDataSource

在之前使用了mybatis的文档中,我们需要手动创建SqlSessionFactory对象来获取SqlSession,然后通过SqlSession获取mapper代理对象,进行数据库操作。// 根据xml配置文件(全局配置文件)创建一个SqlSessionFactory对象// 通过SqlSessionFactory获取SqlSession实例。

Roy0826的博客 730

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

Spring整合MyBatis:SqlSessionFactoryBean【基础】

SqlSessionFactoryBean 是一个负责生产 SqlSessionFactory 的工厂 Bean, 当想从容器中获取 SqlSessionFactory 对象时,Spring 会调用其 getObject() 方法进行获取。

mrguif的博客 3102

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

【MyBatis源码分析】Spring与MyBatis整合深入解析

MapperScannerConfigurer 是 MyBatis-Spring 框架中的一个非常重要的组件,它帮助开发者自动扫描并注册 MyBatis 的 Mapper 接口。通过 MapperScannerConfigurer,我们不需要手动配置每一个 Mapper 接口的 Bean,而是通过配置扫描路径,自动为每个接口创建代理实例,并将其注册为 Spring 的 Bean。

发现问题,面对问题,分析问题,解决问题,总结问题 1572

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

mybatis-spring整合包源码阅读(一)---- SqlSessionFactoryBean相关总结

jar版本:1.3.2 SqlSessionFactoryBean:mybatis 与 spring 整合包里的新增类 作用: 1、加载mybatis相关配置文件,并将mybatis的基本环境属性装配到SqlsessionFactory中 2、为SqlsessionFactory提供所需属性,装配Mybatis运行上下文 ...

编码爱好者 1223

mybatis 数组_Mybatis源码,mappedStatement—mapper.xml 是如何被解析的?

Ext1:本文源码解析基于 mybatis-spring-boot-starter 2.1.1,即 mybatis 3.5.3 版本。Ext2:本文主要是对源码的讲解,着重点会是在源码上。一、从 MybatisAutoConfiguration 说开去,mapper 文件是怎么扫描的?我们知道配置 SqlSessionFactory 是我们集成 Mybatis 时需要用到的常客,SqlSessio...

weixin_39539764的博客 339
上一篇: hive 远程模式安装
下一篇: 手撸一个类似于Dubbo的远程调用
没有腹肌不改名
博客等级 码龄10年 18粉丝 48原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值