当前位置: 首页 > 科技观察

深入讲解Mybatis的架构原理和六大核心流程

时间:2023-03-20 20:06:47 科技观察

MyBatis是Java生态中非常有名的ORM框架。目前在一线互联网公司广泛使用,Mybatis成为了必然的框架。如果你想进入一线大厂,能够熟练使用MyBatis已经是非常基本的技能了。同时大厂也希望自己的开发者对MyBatis框架的原理和核心实现有深刻的理解。从这个角度来说,了解MyBatis的原理,阅读MyBatis的核心源码,更有利于提升职场竞争力。在深入理解Mybatis的源码之前,我们先来了解一下Mybatis的整体结构和工作原理,这有助于我们理解阅读源码过程中的思路和流程。Mybatis架构设计我们把Mybatis的功能架构分为三层:API接口层,数据处理层,基础支撑层,接口层,接口层:主要是和数据库交互,对外提供接口API,开发者使用这些本地API操作数据库,接口层在收到调用请求后会第一时间调用数据处理层完成具体的数据处理。以Mapper接口为例,将配置文件中的每个节点抽象为一个Mapper接口。该接口声明的方法对应Mapper.xml中的节点项。id值对应方法名,parameterType值对应方法的入参类型,resultMap值对应返回值类型。配置完成后,MyBatis会根据接口声明的方法信息,通过动态代理机制生成一个Mapper实例。调用接口方法时,根据方法名和方法的参数类型确定StatementId。底层依然是通过SqlSession.select/update("statementId",parameter)等实现对数据库的操作。数据处理层数据处理层:可以说是MyBatis的核心,负责具体的SQL查找、SQL解析、SQL执行以及执行结果映射处理等,其主要目的是根据调用完成一次数据库操作要求。从大的角度来看,它要完成两个功能:通过传入参数构建动态SQL语句,执行SQL语句和封装查询结果集1.通过传入参数构建动态SQL语句。动态语句生成可以说是MyBatis框架非常重要的一个优雅的设计。MyBatis使用Ognl通过传入的参数值动态构造SQL语句,这使得MyBatis非常灵活和可扩展。参数映射是指java数据类型和jdbc数据类型之间的转换。这里有两个过程:查询阶段查询结果集转换阶段查询阶段通过preparedStatement.setXXX()将java类型数据转换为jdbc类型数据设置值;另一种是将resultset查询结果集的jdbcType数据转换成java数据类型。2.SQL语句的执行和封装的查询结果集动态SQL语句生成后,MyBatis会执行SQL语句,将可能返回的结果集转换成一个List列表。在结果集的处理上,MyBatis支持结果集关系的一对多和多对一的转换,支持的方式有两种,一种是嵌套查询语句的查询,一种是嵌套查询语句的查询结果集。基础支撑层基础支撑层是整个MyBatis框架的基础,负责最基础的功能支撑,包括连接管理、事务管理、配置加载、缓存处理等。这些都是普通的东西,提取出来就是最基本的组件。为上层数据处理层提供最基础的支持。1、缓存机制数据库是实践生成中非常核心的存储,大量的业务数据都会落地到数据库中,因此数据库的性能好坏直接影响到上层业务系统的好坏。我们很多线上业务都处于读多写少的场景。当数据库遇到瓶颈时,缓存是最有效也是最常用的方法之一。正确使用缓存可以在缓存层拦截一些数据库请求。可以减轻一部分数据库的压力,提高系统性能。持久化框架除了使用Redis、Memcached等外部第三方缓存外,一般也会自带缓存。例如,MyBatis提供了一级缓存和二级缓存。具体实现位于基础支撑层的缓存模块中。2.反射工具该模块很好的封装了原生的Java反射,提供了更简洁易用的API,方便上层调用,并对反射操作做了一系列的优化,比如缓存类的元数据,提高反射操作的性能。3.类型转换类型转换模块主要提供了两个功能,一个功能是别名机制,MyBatis为了简化配置文件提供了别名机制。另一个功能是实现JDBC类型和Java类型之间的转换,涉及SQL语句实际参数的绑定和查询结果集的映射。4、日志提供详细的日志输出信息,可集成多种日志框架。其日志模块的主要功能之一是集成第三方日志框架。5.资源加载资源加载模块主要封装了类加载器,决定了类加载器的使用顺序,提供加载类文件和其他资源文件的功能。6.Parserparser模块主要提供两个功能。一个功能是对XPath进行封装,提供MyBatis初始化时解析mybatis-config.xml配置文件和映射配置文件的支持。另一个特性是支持处理动态SQL语句中的占位符。7.事务管理持久层框架一般都提供了一套事务管理机制来实现数据库的事务控制。MyBatis对数据库中的事务实现了一个简单的抽象层,并提供了易于使用的事务接口和实现。一般Java项目都会集成Spring,Spring框架来管理事务。8、Binding在调用SqlSession的相应方法进行数据库操作时,需要指定映射文件中定义的SQL节点。如果有错字,我们只能在运行时找到对应的异常。为了尽早发现这种错误,MyBatis通过Binding模块将用户自定义的Mapper接口与映射配置文件相关联。系统可以通过调用自定义Mapper接口中的方法执行相应的SQL语句来完成对数据库的操作,从而避免了上述问题。需要注意的是,不需要编写Mapper接口的自定义实现。Mapper接口的具体实现MyBatis会自动为其创建一个动态代理对象。9、数据源对于ORM框架来说,数据源的组织是非常重要的一环,它直接影响到框架的性能。数据库连接是一种有限且昂贵的资源。一个数据库连接对象对应一个物理数据库连接。每次操作都会打开一个物理连接,使用完再关闭连接,导致系统性能低下。数据库连接池的解决方案是在应用程序启动时建立足够的数据库连接,并将这些连接组成一个连接池,应用程序动态申请、使用和释放池中的连接。打开Mybatis源码,找到datasource包可以看到连接池的实现,如下图:Mybatis核心执行流程Mybatis整体执行流程如下:1.MyBatis配置文件config.xml:configure全局配置文件配置了MyBatis的运行环境等信息。mapper,xml:sql映射文件,配置操作数据库的sql语句,该文件需要在config.xml中加载。2、SqlSessionFactory通过MyBatis环境等配置信息构造SqlSessionFactory(会话工厂)。3、SqlSession通过会话工厂创建SqlSession(session),对数据库进行增删改查操作。4.Exector执行器MyBatis底层自定义了Exector执行器接口,专门对数据库进行操作。Exector接口有两种实现,一种是基本执行器(默认),另一种是缓存执行器。SqlSession底层是通过Exector接口对数据库进行操作。5、MappedStatementMyBatis的一个底层封装对象,封装了MyBatis的配置信息和sql映射信息。mapper.xml中的insert/select/update/delete标签对应一个MappedStatement对象。标签的id是MappedStatement的id。MappedStatement定义了sql执行的入参,包括HashMap、基本类型、pojo、Executor。MappedStatement在执行sql之前将输入的Java对象映射到sql。输入参数映射是JDBC编程为preparedStatement设置参数。MappedStatement定义了SQL执行的输出结果,包括HashMap、基本类型、pojo。Executor通过MappedStatement将SQL执行后的输出结果映射到Java对象中。输出结果映射是JDBC编程对结果的分析处理过程。至此,我已经从全局的角度对Mybatis架构进行了拆解,后续会着重分析其核心源码,做到先全局后局部,更有利于掌握其实现核心原则。希望这个框架系列能对你有用。