MyBatis3源码解析(8)MyBatis与Spring的结合

深入解析MyBatis源码与实战 摘要:本文系统解析MyBatis核心架构与实现原理,涵盖配置解析、SQL执行、结果映射三大模块。通过动态SQL生成、缓存机制(一级/二级缓存)、插件开发(Interceptor接口)等典型示例,深入剖析源码实现。结合SpringBoot集成场景,展示CRUD操作、动态SQL拼接、事务管理、多数据源配置等实战方案,并给出批量操作优化(BatchExecutor)、类型处理器扩展等高级特性实现。特别说明流程图关键节点:从SqlSessionFactory构建到Executor执行,通过StatementHand 阅读详情

简介

在上几篇文章中,解析了MyBatis的核心原理部分,我们大致对其有了一定的了解,接下来我们看看在日常的开发中MyBatis是如何与Spring框架结合的

源码解析

在我们的日常开发中,使用Spring框架结合MyBatis,只需简单的进行相关的配置,在代码中使用注解即可轻松使用,而不用像下面示例中的,需要很多的代码:

public class MybatisTest {

    // 从SqlSessionFactory中获取Mapper进行使用
    @Test
    public void test() {
        try(SqlSession session = buildSqlSessionFactory().openSession()) {
            PersonMapper personMapper = session.getMapper(PersonMapper.class);
            personMapper.createTable();
            personMapper.save(Person.builder().id(1L).name(new String[]{"1", "2"}).build());
            personMapper.save(Person.builder().id(2L).name(new String[]{"1", "2"}).build());

            Map<String, Object> query = new HashMap<>(2);
            query.put("id", 1);
            query.put("name", new String[]{"1", "2"});
            System.out.println(personMapper.getPersonByMap(query));
        }
    }

    // 初始化SqlSessionFactory
    public static SqlSessionFactory buildSqlSessionFactory() {
        String JDBC_DRIVER = "org.h2.Driver";
        String DB_URL = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1";
        String USER = "sa";
        String PASS = "";
        DataSource dataSource = new PooledDataSource(JDBC_DRIVER, DB_URL, USER, PASS);
        Environment environment = new Environment("Development", new JdbcTransactionFactory(), dataSource);
        Configuration configuration = new Configuration(environment);
        configuration.getTypeHandlerRegistry().register(String[].class, JdbcType.VARCHAR, StringArrayTypeHandler.class);
        configuration.addMapper(PersonMapper.class);
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        return builder.build(configuration);
    }
}

在上面的代码中,我们可以明显的看到大段的SqlSessionFactory初始化和Mapper的获取的繁琐代码,但我们在Spring中没有这些繁琐的操作,如下变可以使用:

@AllArgsConstructor
@Service
public class PersonService {

    private final PersonMapper personMapper;

    public void select() {
        personMapper.getPersonById(0);
    }
}

可以说非常省心和简单了

以前自己也不知道其原理,通过这段时间的学习,了解了MyBatis的原始使用和Spring的相关原理,知道了其背后的原理,在开发中使用起来感觉心中比以前有数了,希望通过这些源码解析的文章,也能对大家有所帮助

SqlSessionFactory的初始化

这部分涉及到Spring的Bean和Spring Boot自动配置

可以尝试去自己写一个Spring Boot Starter,这样会有比较大帮助(以前好像写过一篇,但找不到了,可以参考下下面其他人的链接):

这里我们直接去看包:org.mybatis.spring.boot.autoconfigure

可以看到下面一段我们熟悉的内容:

可以看到Spring 在启动时便自动初始化了SqlSessionFactory,其中的细节这里就不赘述了

    @Bean
    @ConditionalOnMissingBean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(dataSource);
        factory.setVfs(SpringBootVFS.class);
        if (StringUtils.hasText(this.properties.getConfigLocation())) {
            factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
        }

        this.applyConfiguration(factory);
        if (this.properties.getConfigurationProperties() != null) {
            factory.setConfigurationProperties(this.properties.getConfigurationProperties());
        }

        if (!ObjectUtils.isEmpty(this.interceptors)) {
            factory.setPlugins(this.interceptors);
        }

        if (this.databaseIdProvider != null) {
            factory.setDatabaseIdProvider(this.databaseIdProvider);
        }

        if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
            factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
        }

        if (this.properties.getTypeAliasesSuperType() != null) {
            factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType());
        }

        if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
            factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
        }

        if (!ObjectUtils.isEmpty(this.typeHandlers)) {
            factory.setTypeHandlers(this.typeHandlers);
        }

        if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
            factory.setMapperLocations(this.properties.resolveMapperLocations());
        }

        Set<String> factoryPropertyNames = (Set)Stream.of((new BeanWrapperImpl(SqlSessionFactoryBean.class)).getPropertyDescriptors()).map(FeatureDescriptor::getName).collect(Collectors.toSet());
        Class<? extends LanguageDriver> defaultLanguageDriver = this.properties.getDefaultScriptingLanguageDriver();
        if (factoryPropertyNames.contains("scriptingLanguageDrivers") && !ObjectUtils.isEmpty(this.languageDrivers)) {
            factory.setScriptingLanguageDrivers(this.languageDrivers);
            if (defaultLanguageDriver == null && this.languageDrivers.length == 1) {
                defaultLanguageDriver = this.languageDrivers[0].getClass();
            }
        }

        if (factoryPropertyNames.contains("defaultScriptingLanguageDriver")) {
            factory.setDefaultScriptingLanguageDriver(defaultLanguageDriver);
        }

        this.applySqlSessionFactoryBeanCustomizers(factory);
        return factory.getObject();
    }

Mapper的生成使用

这部分涉及到Spring的依赖注入相关的原理了,自己以前写过一个demo,但文章还没完善,后面抽空完善后,再发出来

简答来说,核心是:

  • 1.应用启动时,自动生成需要的类实例放入容器中, 比如加了Service注解的类
  • 2.对类实例进行初始化,在构造函数中,将其需要的类实例给传递进去

比如下面的:

@AllArgsConstructor
@Service
public class PersonService {

    private final PersonMapper personMapper;
}

在Spring容器中已经有了类 PersonService 和 PersonMapper 的实例

在初始化阶段,调用 PersonService 构造函数时,发现需要 PersonMapper,由于从容器中取PersonMapper给其传递进去

大体的意思应该是这样,可能细节上会有些出入

下面是大致一些Debug的信息,通过调试就会发现,SqlSessionFactory 和 Mapper 初始化和获取等代码都是在应用程序其中就会执行触发

这个是PersonService这个bean初始化的相关栈函数:

   @Nullable
    protected Object resolveAutowiredArgument(MethodParameter param, String beanName, @Nullable Set<String> autowiredBeanNames, TypeConverter typeConverter, boolean fallback) {
        Class<?> paramType = param.getParameterType();
        if (InjectionPoint.class.isAssignableFrom(paramType)) {
            InjectionPoint injectionPoint = (InjectionPoint)currentInjectionPoint.get();
            if (injectionPoint == null) {
                throw new IllegalStateException("No current InjectionPoint available for " + param);
            } else {
                return injectionPoint;
            }
        } else {
            try {
                return this.beanFactory.resolveDependency(new DependencyDescriptor(param, true), beanName, autowiredBeanNames, typeConverter);
            } catch (NoUniqueBeanDefinitionException var8) {
                throw var8;
            } catch (NoSuchBeanDefinitionException var9) {
                if (fallback) {
                    if (paramType.isArray()) {
                        return Array.newInstance(paramType.getComponentType(), 0);
                    }

                    if (CollectionFactory.isApproximableCollectionType(paramType)) {
                        return CollectionFactory.createCollection(paramType, 0);
                    }

                    if (CollectionFactory.isApproximableMapType(paramType)) {
                        return CollectionFactory.createMap(paramType, 0);
                    }
                }

                throw var9;
            }
        }
    }

调试的相关信息如下:

image.png

这个beanName是PersonService,需要的构造函数参数是 PersonMapper

一直跟着下面,它会从SqlSessionTemplate中取

    public <T> T getMapper(Class<T> type) {
        return this.getConfiguration().getMapper(type, this);
    }

然后就跳到我们熟悉的 Mybatis类中 Configuration:

  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
  }

总结

本篇中大致探索了:

  • MyBatis初始化 SqlSessionFactory:Spring boot 自动配置
  • Mapper初始化和使用:基于依赖注入,方便快捷的使用
Mybatis源码解析之SpringBoot集成mybatis-spring-boot-starter分析 Mybatis源码解析之核心类分析 Mybatis源码解析之初始化分析 Mybatis源码解析之执行流程解析 Mybatis源码解析之数据库连接和连接池 Mybatis源码解析之事务管理 Mybatis源码解析之缓存机制(一):一级缓存 Mybatis源码解析之缓存机制(二):二级缓存 Mybatis源码解析之插件机制 Mybatis源码解析之mapper接口的代理模式 Mybatis源码解析之D... 阅读详情

相关推荐

Spring 整合 MyBatis 底层源码解析

在Spring整合Mybatis后,如果执行某个方法时,该方法上没有加@Transactional注解,也就是没有开启Spring事务,那么后面在执行具体sql时,每执行一个sql时都会新生成一个SqlSession对象来执行该sql,这就是我们说的一级缓存失效(也就是没有使用同一个SqlSession对象),而如果开启了Spring事务,那么该Spring事务中的多个sql,在执行时会使用同一个SqlSession对象,从而一级缓存生效。大家好,我是柳岸花开。

木卯的专栏 1199

《MyBatis3源码深度解析》图书简介

一、图书封面 二、书籍目录 前言 4 第1篇 Mybatis3源码 7 第1章 搭建Mybatis源码环境 7 1.1 Mybatis3简介 7 1.2 环境准备 7 1.3 获取Mybatis源码 8 1.4 导入Mybatis源码到IDE 10 1.5 HSQLDB数据库简介 13 1.6 本章小结 16 第2章 JDBC规范详解 17 2.1 JDBC API简介 17 2.1.1 建立数...

Coding... 4620

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

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

喵手的博客 2012

【mybatis3】MyBatis源码分析

MyBatis源码分析

wufaqidong1的博客 328

深入解析Spring与MyBatis的整合及源码实现

在开始探索Spring框架的核心之前,我们必须先了解它是什么以及它为何对现代Java开发至关重要。Spring是一个开源的、全面的企业级应用开发框架,提供了一种简化Java应用程序开发的方式。它不仅帮助开发者编写可维护的代码,还能通过依赖注入(DI)和面向切面编程(AOP)来管理业务对象之间的复杂关系。MyBatis 还具有一些高级特性,例如:动态 SQL: MyBatis 支持动态 SQL 标签,如<if><choose><foreach>

weixin_42389113的博客 883

MyBatis源码分析.pdf

MyBatis源码分析.pdf

Mybatis3源码全解析

Mybatis架构: 图自:MyBatis整体架构_tiankong_12345的博客-优快云博客_mybatis架构 Mybatis架构分三层: 第一层:SqlSession 这是使用mybatis的主要接口,通过这个接口我们可以执行命令,获取mapper或者管理事务。 Through this interface you can execute commands, get mappers and manage transactions. 第二层:核心处理层 配置解析模块:myb

MieMieFly的专栏 1316

mybatis 3.x源码深度解析与最佳实践.html

redis设计与实现解读,解析SDSss

MyBatis3源码解析(1)探索准备

本篇文章将使用原生的JDBC方式操作数据库,然后在使用Mybatis提供的方式操作数据库,通过对比两部分的操作,大致得到Mybatis所做的主要工作,为接下来的源码解析做准备

github_35735591的博客 320

Mybatis源码解析

mybatis源码解析视频的讲解是由某知名老师讲解。包你学完可以完全理解mybatis框架实现原理等。

mybatis-3.4.4(包含源码,中文帮助文档PDF,JAR包)[超清晰版]

文档是Mybatis在github上的官方中文教程文档,很详细的讲解的mybatis的用法。pdf文档是文字版可复制,是我通过工具将官方的中文文档转化为pdf的,如果好用的话,希望大家给个好的评论(好资源就是要分享)

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

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

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

mybatis 3.x源码深度解析与最佳实践1.html.zip

还不错的MyBatis源码分析资料,对学习MyBatis有不错的帮助,可以参考学习,不懂的可以交流哈 V:study_51ctofx

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

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

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

雷电模拟器+Auto.js避坑指南:用桥接模式解决PC与模拟器连接超时问题

本文详细解析了雷电模拟器与Auto.js联调中的桥接模式应用,解决PC与模拟器连接超时问题。通过桥接模式配置、高频故障排查及多开环境下的高阶配置,提升开发效率与稳定性,特别适合需要稳定网络连接的Auto.js开发者。

weixin_28836989的博客 630

UVM和System verilog笔记总结(四)

virtual sequence 即虚seq,用于管理多个实sequence的执行顺序。 下面有三个sequence,此时需要virtual sequence去管理这三个的顺序。 virtual sequence和virtual sequencer需要成对写,使用例化实的sequence和sequencer控制: 此时在virtual sequence里面启动,而不是之前在test.sv里面用default或start函数启动。具体方法如下:先例化 再启动,用 `uvm_do_on 实sequence

weixin_42655118的博客 642

Spring之整合Mybatis底层源码解析

整合核心思路由很多框架都需要和Spring进行整合,而整合的核心思想就是把其他框架所产生的对象放到Spring容器中,让其成为Bean。​。

输入知识,消化知识,输出知识,分享知识,教人让我学习更好,业精于勤荒于嬉,行成于思毁于随 1543

在LinuxMint 22.1(Ubuntu24.04)上安装使用同花顺远航版

Linux用户成功在LinuxMint22.1系统上通过Wine9.0运行同花顺远航版,解决了长期困扰的股票行情软件问题。此前Linux原生版同花顺功能简陋且停止更新,Wine版通达信存在显示问题。作者作为自由软件支持者,通过调整Wine配置文件解决了高分屏显示异常问题,实现了远航版的正常使用。期待同花顺能重启Linux原生版开发,支持更多处理器架构,完善国产软件生态。该方案为Linux股票软件用户提供了实用参考。

5129

Mybatis3 源码解析系列

Mybatis作为一个优秀的Java持久化框架,在我们的日常工作中相信都会用到,本次源码解析系列,就开始探索下Mybatis

github_35735591的博客 1076

UCOS-III 系统移植

UCOSIII系统移植到GD32F303详细过程 工程代码:https://github.com/jslaobing/techIot_ucosiii_porting

TechIoT - 探索物联网与嵌入式系统 2086

【2023校招】网易雷火_研发岗_笔试题解

几个月没写题,果然水平不在线了hh,AK更难实现喽,当天只AK了疯狂游戏; 题目描述和数据等尽量多的CV到了DEVC里,可能不够细节和准确; 下面进入正题,分享我们此次笔试的题目描述和代码设计吧~.........

米莱虾 4544

MyBatis 源码深度解析:从 Spring Boot 实战到底层原理

本文深入解析MyBatis框架,从Spring Boot集成实践到核心源码分析。首先介绍MyBatis与Spring Boot的整合方式,包括依赖配置、实体类定义、Mapper接口编写及XML映射文件配置。重点剖析MyBatis的核心特性:动态SQL、结果映射、两级缓存机制和插件体系。最后解析MyBatis的执行流程,包括SqlSession获取、SQL解析执行及结果处理等核心环节,揭示其"接口层-核心处理层-基础支撑层"的三层架构设计。全文帮助开发者深入理解MyBatis的工作原理,提

weixin_45149504的博客 1237

C#客户端对接工厂MES的方法

本文介绍了使用C#实现WebApi客户端与工厂MES系统交互的方法。主要包括四个步骤:1)配置工控机IP地址;2)获取服务器URL;3)创建HttpHelper帮助类实现单例模式HttpClient,提供异步POST请求方法;4)通过实例化帮助类实现设备状态数据的JSON格式发送与接收。该方案采用异步通信方式,支持超时处理,能够满足大多数MES系统交互需求,帮助工程师快速完成设备与MES系统的数据对接。文中给出了核心代码片段和完整的数据交互流程示例。

weixin_39832501的博客 264
上一篇: MyBatis3源码解析(7)TypeHandler注册与获取
下一篇: MyBatis Demo 编写(1)基础功能搭建
_萧_
博客等级 码龄10年 55粉丝 157原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值