mybatis分析

1.1 应用架构分析


mybatis是一个优秀的持久层框架,底层基于JDBC实现与数据库的交互,并在JDBC操作的基础上做了封装和优化,其应用架构如图所示

        应用程序(任意方法:main方法/单元测试方法)--获取mybatis相关的API(任何框架都有一组对外的API,使用这样的一组API来执行数据访问,mybatis底层其实是封装了JDBC相关API的一些调用,底层借助JDBC来访问具体的数据库)--使用JDBC--使用JDBC的驱动程序--访问数据库

为什么使用mybatis来封装JDBC操作呢?

        我们知道传统的JDBC其实从执行性能上来说还是非常好的,但是它有些步骤相对来说会比较复杂,比方说:我们使用Statement去发送sql时,要为sql语句中的?号赋值,比方说:我们使用Statement发送sql交给数据库去执行sql,那么拿到一个结果时,要从结果集中去取数据,然后映射到内存中这样的一个对象中,这个过程是相对比较复杂的,而且重复性又比较大,所以说在我们传统的应用当中,也就是说在JDBC参数设置(参数映射),结果映射, SQL编写相对来说它的灵活度不够,而且很多工作的冗余性比较大,所以说有了像mybatis这样的一系列框架

在mybatis里面做了一种方式:让sql和传统的java代码实现分离,把sql语句可以写到一些映射文件中去(mapper.xml),而且mybatis里面还做了一件非常好的事,就是它提供了一种动态SQL,可以基于用户的需求,动态的去拼接SQL,更好的去满足用户的业务,以实现以不变应万变

说明: mybatis之所以能够成为互联网项目中持久层应用的翘楚,个人认为其核心竞争力应该是它灵活的SQL定制(动态SQL),参数及结果集的映射

1.2 产品架构分析



互联网项目中的任何一个框架都可以看成是一个产品,每个产品都有它自己的产品架构,mybatis也不例外,它的产品架构主要可以从接口应用,SQL处理以及基础服务支撑等几个角度进行分析,如下图所示:

接口应用层是面向应用程序员(运用mybatis的程序员)

SQL处理层是mybatis底层做的一些实现,重点是对SQL语句进行解析,参数进行映射,结构集映射处理等等

基础支撑层(基础服务层):在基础服务层里面,因为mybatis框架它实现的是与数据库的交互,所以我们把mybatis称为持久层的框架,所以他底层需要一些连接的配置,还有一些缓存的配置,日志的配置,以及一些别名的配置

所有的软件都可能有基础支撑层,又称之为平台支撑层,在平台之上可能会提供一些具体的功能,那么这些具体功能对外的一些呈现就是一些接口

说明: 所有想成为平台架构师的程序员,在应用一个互联网框架的过程中都应对框架的设计理念,实现思路有一个很好的认知,并基于认知强化实践过程,扩展产品架构思维

1.3 技术架构分析


我们有了对产品架构的认知以后,还要了解产品架构背后的技术架构组成及原理,并能够迅速基于产品功能进行落地实现,然后优化和推广

 

SqlMapConfig.xml : 配置文件,配置的是mybatis的一些基础服务,  面向程序员的

SqlMap.xml: 映射文件,配置的是mybatis中与数据表中映射的一些SQL映射元素 . 面向程序员的

XxxBuilders: 去解析上面的配置文件解析,把配置文件的内容封装到下面三个对象中

Mapped Statement : 映射语句

params map: sql语句执行时需要的参数

result maps : SQL执行的结果集

Configuration: 核心配置类,可以理解为是配置信息对外的出口,其他应用程序可以通过这个配置对象来拿到具体的配置信息

Mybatis 中的API架构


红色的圆圈表示的就是接口

通过SqlSessionFactoryBuilder对象的build方法(参数是Configuration对象)来创建SqlSessionFactory对象(其实是它的实现类DefaultSQLSessionFactory对象)

通过SqlSessionFactory对象的openSession()来创建SqlSession对象(其实是它的实现类DefaultSqlSession对象)

SqlSession: 使用SqlSession实现与数据库的会话过程

2.1 核心对象应用


SqlSessionFactory工厂对象创建分析(负责创建SqlSession)

mybatis中两大核心文件:配置文件(mybatis-config.xml 文件名随意),映射文件(XXXMapper.xml)

mybatis-config.xml 配置文件:一些mybatis的一些基础支撑层的配置,比方说,配置连接池,mybatis的缓存,日志,延迟加载,类型转换器,拦截器,别名,还可以配置映射文件的位置和路径

mybatis-config.xml是mybatis这个框架初始化时的入口文件,当我们初始化mybatis这个框架的时候会首先执行这个配置文件,从这个配置文件开始加载配置信息,包含一些映射信息,比方说在mappers这个位置要去加载XXXMapper.xml配置文件,一个mappers中可以有多个映射文件

XXXMapper.xml: 里面写的是一些映射元素,比方说select,update,delete,insert这些映射元素,

配置文件和映射文件都需要流来读取这些配置文件,需要通过一定的解析技术来解析这些文件,把这些解析出来的数据要做一个封装的过程

在mybatis里面有这样的一个配置类XMLConfigBuilder,这个类就是要读取mybatis-config.xml这个配置文件的,将environments元素里面的内容封装到Environment这个类里面

XmlMapperBuilder这个类负责解析XXXMapper.xml这个映射文件中的映射元素(比方说select,update,delete,insert),并将这些元素里面的信息封装到MappedStatement这个对象里面(每个映射元素一个对象),这个MappedStatement对象里面包含这个映射元素的id,结果集,映射的类型,参数的类型,SQL语句等等,因为这个MappedStatement对象由很多,所以会储存到Map中,key就是命名空间+元素的id,value就是该元素的MappedStatement对象,

封装好了的配置信息(environments,Map<Stirng,MappedStatement>),都会封装到Configuration这个核心配置文件中,Configuration这个配置类中包含了很多配置信息,系统通过Configuration来创建工厂,怎么构建呢?

通过SqlSessionFactoryBuilder的build(Configuration)方法去读取Configuration里面的信息,基于Configuration的配置信息来构建SqlSessionFactory(构建的是它的实现类DefaultSqlSessionFactory对象)工厂对象,然后基于这个工厂再去构建SqlSession对象

设计思想: 有配置信息就得读取配置信息,读了配置信息就得解析,解析完就要封装,封装完就要用

需要注意的是这里面有很多Builder对象,不管是XMLConfigBuilder,还是XmlMapperBuilder,还是SQLSessionFactoryBuilder这里面有一种设计模式,叫建造模式,一般情况下,我们基于配置文件去构建对象,因为配置文件里面是配置了很多配置信息,我们创建这个对象的过程是相对比较复杂的过程,那么我们常用的一种模式,就是Builder模式,基于Builder模式我们创建了很多配置文件,后面基于配置对象,我们去创建一些工厂对象,那么这里面又用到了一种设计模式,叫做工厂模式(其实这个模式我们叫简单工厂),基于这个工厂来创建SqlSession对象

代码测试:

package com.cy.test;

import java.io.IOException;
import java.sql.Connection;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;

public class TestBaseWithXml {
	/**
	 * 借助此对象创建SqlSession(通过此对象
	 * 实现与数据库之间的会话)
	 */
	protected SqlSessionFactory sqlSessionFactory;
	/**
	 * 此方会在@Test注解修饰的方法之前执行,
	 * 通常用于做一些初始化操作(方法名自己定义)
	 */
	@Before
	public void init()throws IOException{
		sqlSessionFactory=new SqlSessionFactoryBuilder().
				build(Resources.getResourceAsStream("mybatis-configs.xml"));
		//系统底层建造者模式构建工厂对象(此对象构建过程相对复杂)
		System.out.println(sqlSessionFactory);
	}
	@Test
	public void testSqlSessionConnection(){
		SqlSession session=sqlSessionFactory.openSession();
		Connection conn=session.getConnection();
		System.out.println(conn);
	}
}

代码分析:

1.点击build()方法进去,

是不是基于XMLConfigBuilder来解析的,在点击parser.parse()方法进去看看:

返回值是Configuration对象,build方法的参数是Configuration类型吧,再点击build(parser.parse())方法进去

返回的类型是不是SqlSessionFactory对象

SqlSessionFactory工厂对象创建的时序图

Resources对象调用.getResourcesAsStream(resource)方法去读取配置文件,返回一个流对象

SqlSessionFactoryBuilder对象的build(inputstream)方法

build(inputstream)方法内部new XmlConfigBuilder(inputstream)对象,调用其parse()方法来解析资源,并返回一个configuration对象

然后调用build(config)方法去创建一个 new DefaultSqlSessionFactory(config)对象,

build()方法获得DefaultSqlSessionFactory对象,并返回给用户


SqlSession对象应用过程分析(是实现与数据库进行会话的入口对象)

我们可以把SqlSession理解为是一个会话对象,因为我们要基于SqlSession,通过SQL语句实现与数据库的会话,所以说我们又把它理解为是一个会话对象,当我们使用SqlSession对象去访问数据库的时候 ,我们表示一般把这个过程理解是一个会话过程,每一次会话的开启都离不开SqlSession,所以说这个对象是一个实现与数据库会话的一个入口对象

我们知道我们可以通过SqlSessionFactory对象来创建SqlSession对象,可其实底层是创建的DefaultSqlSession对象,而一个SqlSessionFactory可以出创建多个DefaultSqlSession对象,也就是说一个工厂对应着多个会话对象,因为将来系统可能会有多个用户同时来访问,那么有多个用户同时去访问数据库的话,我们就需要多个会话对象,而多个会话对象其实就是多个SqlSession对象,

执行流程: 例如查询流程

调用SqlSession的selectXXX()方法,而调用的相关方法时,其实底层是基于执行器去执行的,就是Executor对象,而Executor是一个接口,这个接口下面有很多实现类,那么它会基于你的SQL请求的不同,来创建不同的执行器对象,

在上图中,当我们执行数据访问时,当我们调用相关的select方法时,它首先会拿到的是Executor对象,具体他是使用CacheExecutor对象,还是SimpleExecutor对象或者BatchExecutor对象,他取决于你的SqlSession对象的创建方式,比方说你的程序中默认开启了二级缓存,那么使用SqlSession对象去执行数据查询操作时,他底层会创建CacheExecutor对象,假如你没有开启二级缓存,他系统底层会默认创建SimpleExecutor对象,假如你调用openSession时指定了Executor的类型,你要执行什么动作呢?批处理的动作,那它系统底层还会创建BatchExecutor对象,总之这些Executor对象就是为了服务于SqlSession对象的,可以理解为SqlSession对象来发号指令,由Executor对象来执行,具体执行那一个它会根据你具体的配置的不同来创建不同的Executor对象,这块其实是有一个设计模式,叫策略模式

而Executor在做数据访问时,还需要获取StatementHandler(处理器),而这个处理器也是一个接口,Executor是通过StatementHandler来执行数据访问操作的,那么当我们拿到StatementHandler时,我们要执行哪一个处理器呢?也要取决于你具体的配置,比方说你的SQL语句中是不包含一些问号的SQL语句,那么它系统底层可能会直接创建一个SimpleStatementHandler对象,没有预编译的SQL,那么假如你的SQL语句中带有一些预编译的SQL带问号的,它可能会给你创建一个PreparedStatementHandler对象,那么假如你是想要调用的是一些存储过程,它会创建CallableStatementHandler对象(这个对象了解就行,不常用).

StatementHandler是封装的Statement的操作,它是执行SQL操作,那么SQL从哪来呢?它是从MappedStatement 

     

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值