MyBatis 工作流程

本文详细分析了MyBatis的工作流程,包括配置解析、SqlSession的使用及Executor执行SQL的过程。同时,介绍了MyBatis的分层架构,强调了核心处理层在参数映射、SQL解析与执行上的作用。此外,文章深入探讨了一级缓存和二级缓存的机制,指出一级缓存局限于同一SqlSession,二级缓存则可在namespace级别共享,并提供了开启及关闭二级缓存的方法。最后,提到了自定义二级缓存和第三方缓存如Redis的集成。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

mybatis工作流程分析

首先MyBatis启动的时,需要解析配置文件,包括全局配置文件和映射器配置文件,解析成Configuration对象。

然后,通过SqlSession对象,对数据进行操作(SqlSession是我们操作数据库的接口,它在应用程序和数据库中间,代表我们跟数据库之间的一次链接)。SqlSession的创建需要通过SqlSessionFactory创建,SqlSessionFactory里面包含所有的配置信息,通过SqlSessionFactoryBuilder创建工厂类。

MyBatis是对JDBC的封装,里面包含JDBC的核心对象,例如执行SQL的Statement,结果集ResultSet。在MyBatis里面,SqlSession只是提供给应用的一个接口,不是SQL的真正执行对象。SqlSession持有的Executor对象,是真正对数据库进行操作的。Executor对象里面封装了对数据库的具体操作。

 

mybatis架构分层和模块划分

mybatis分为接口层、核心处理层、基础层。

接口层

与我们打交道最多的就是接口层。核心对象是SqlSession,SqlSession定义了对数据库的操作方法。接口层在收到调用请求的适合,会调用核心处理层的相应模块完成具体的数据库操作。

核心处理层

跟数据库操作相关的动作都在这一层完成。

核心处理层主要工作:

  1 把接口传入的参数解析并映射成JDBC类型

  2 解析xml文件中的SQL语句,包括插入参数和动态SQL的生成

  3 执行SQL语句

  4 处理结果集,并映射成java对象

基础支持层

基础支持层主要是一些抽取出来的通用功能,用来支持核心处理层的功能。比如数据源、日志、缓存,反射、IO、事务等功能。

MyBatis缓存详解

cache缓存

 缓存是一般的ORM 框架都会提供的功能,目的就是提升查询的效率和减少数据库的压力。跟Hibernate 一样,MyBatis 也有一级缓存和二级缓存,并且预留了集成第三方缓存的接口。

缓存体系结构

MyBatis跟缓存相关的类都在cache包里面,其中有一个Cache接口,只有一个默认的实现类PerpetualCache,它是用HashMap实现的。

除此之外还有很多的装饰器,通过这些装饰器可以额外实现很多功能:回收策略、日志记录、定时刷新等

装饰器模式:是指在不改变原有对象的基础之上,将功能附加到对象上,提供了比继承更有弹性的替代方案(扩展原有对象功能)。

但是无论怎么装饰,经过多少层装饰,最后使用的还是基本的实现类(默认PerpetualCache)。

所有缓存实现类总体上可分为三类:基本缓存、淘汰算法缓存、装饰器缓存。

缓存实现类

描述

作用

装饰条件

基本缓存

缓存基本实现类

默认是PerpetualCache,也可以自定义比如RedisCache、EhCache等

LruCache

LRU策略的缓存

当缓存到达上限的时候,删除最近最少使用的缓存(Least Recently Use)

eviction=”LRU”(默认)

FifoCache

FIFO策略的缓存

当缓存到达上线的时候,删除最先入队的缓存

eviction=”FIFO”

SoftCache

WeakCache

带清理策略的缓存

通过JVM的软引用和弱引用来实现缓存,当JVM内存不足时,会自动清理这些缓存,基于SoftReference和WeakReference

eviction=”SOFT”

eviction=”WEAK”

LoggingCache

带日志功能的缓存

比如:输出缓存命中率

基本

SynchronizedCache

同步缓存

基于synchronized关键字实现,解决并发问题

基本

BlockingCache

阻塞缓存

通过个get/put方式中枷锁,保证只有一个线程操作缓存,基于java重入锁实现

Blocking =true

SerializedCache

支持序列化的缓存

将对象序列化以后存到缓存中,取出时反序列化

ReadOnly=false(默认)

ScheduledCache

定时调度的缓存

在进行get/put/remove/getSize等操作前,判断缓存时间是否超过了设置的最长缓存时间(默认时一小时),如果是则清空缓存--即每隔一段时间清除一次缓存

Flushinterval不为空

TransactionalCache

事务缓存

在二级缓存中使用,可一次存入多个缓存,移除多个缓存

在TransactionalCacheManager中用map维护对应关系

 

一级缓存

一级缓存也叫本地缓存,MyBatis的一级缓存是在会话(SqlSession)层面进行缓存的。MyBatis的一级缓存是默认开启的,不需要任何的配置。

首先我们必须去弄明白一个问题,在MyBatis执行的流程里面,涉及到这么多的对象,那么缓存PerpetualCache应该放在哪个对象里面去维护?如果要在同一个会话里面共享一级缓存,这个对象肯定在SqlSession里面创建的,作为SqlSession的一个属性。

DefalultSqlSession里面只有两个属性,Configuration是全局的,所以缓存只可能放在Executor里面维护---SimplaExecutor/ReuseExecutor/BatchExecutor的父类BaseExecutor的构造函数中持有了PerpetualCache。

在同一个会话里面,多次执行相同的SQL语句,会直接从内存取到缓存的结果,不会再发送SQL到数据库。但是不同的会话里面,即使执行的SQL一模一样,也不能使用到一级缓存。

一级缓存验证

判断是否命中缓存:

1 在同一个session中共享

2 不同session不能共享

一级缓存在BaseExecutor的queryFromDatabase()中存入。在queryFromDatabase()之前会get().

3 在同一个会话中,update(包括delete)会导致一级缓存被清空

一级缓存是在BaseExecutor中的update()方法中调用clearCache()清空的(无条件),query中会判断

4 如果跨会话更新了数据,导致读取到脏数据(一级缓存不能跨会话共享)

使用一级缓存的时候,因为缓存不能跨会话共享,不同的会话之间对于相同的数据可能有不一样的缓存。在有多个会话或者分布式环境下,会存在脏数据的问题。如果要解决这个问题,就要用到二级缓存。

二级缓存

二级缓存是用来解决一级缓存不能跨会话共享的问题,范围是namespace级别的,可以被多个SqlSession共享(只要是同一个接口里面的相同方法,都可以共享),生命周期和应用同步。

二级缓存在SqlSession的外层,可以对多个SqlSession共享。在查询时先查询二级缓存,二级缓存取不到,再去一级缓存中取数据。MyBatis用了一个装饰器的类来维护,就是CachingExecutor。如果启用了二级缓存,MyBatis在创建Executor对象的时候会对Executor进行装饰。

CachingExecutor对于查询请求,会判断二级缓存是否有缓存结果,如果有就直接返回,如果没有则委派交给真正的查询器Executor实现类,比如SimpleExecutor来执行查询,再走到一级缓存的流程。最后把结果缓存起来,并且返回给用户。

开启二级缓存的方法

第一步:在mybatis-config.xml中配置(默认时true)

第二步:在Mapper.xml中配置<cache/>标签

Mapper.xml配置了<cache>之后,select()会被缓存。update()、delete()、insert()会刷新缓存。

如果Mapper.xml没有配置<cache>,二级缓存还是开启的,只是启动的时候不会创建这个mapper的Cache对象,最终会影响到CachingExecutor.query方法里面的判断

如果某些查询方法对数据的实时性很高,不需要二级缓存,可以在单独的查询方法上显式的关闭二级缓存(默认时true)

第三方缓存做二级缓存

除了MyBatis自带的二级缓存之外,我们也可以通过实现Cache接口来自定义二级缓存。

MyBatis官方提供了一些第三方缓存集成方式,比如ehcache和redis:

https://github.com/mybatis/redis-cache

pom文件引入依赖:

Mapper.xml配置,type使用RedisCache:

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值