Mybatis体系结构与工作原理

Mybatis体系结构与工作原理

宏观的架构与微观的原理

工作流程

Configuration

SqlsessionFactory

Sqlsession

Executor

StatementHandler

https://www.processon.com/view/link/604030a36376893122d8c05e
在这里插入图片描述

架构分层与模块划分

接口层

核心层

与数据库操作的相关动作都是在这里层完成的。

主要处理:
1、把接口传入的参数解析并且映射成JDBC类型

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

3、执行SQL语句

4、处理结果集,并映射为Java对象

基础层

主要是抽取一些通过的功能,来支持核心层的功能。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GHx2eU5S-1614819366646)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210303200411999.png)]

缓存详解

目的

提升查询的效率和减少数据库的压力。

体系结构

基本缓存

默认的基础使用缓存

PerpetualCache

淘汰算法缓存

LruCache

FifoCache

SoftCache

WeakCache

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wrGipxYK-1614819366648)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210303201243300.png)]

装饰器缓存

LoggingCache

SynchronizedCache

BlockingCache

ScheduledCache

TransactionalCache

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6MPanb3N-1614819366660)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210303201534846.png)]

一级缓存

又名本地缓存,一级缓存是会话级别的。默认是开启状态,localCacheScope=STATEMENT(关闭一级缓存)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zFNuXNVQ-1614819366664)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210303201941503.png)]

只有在相同会话里,多次执行相同语句,会从内存中取到缓存结果,不会去查询数据库。

1、如何命中一级缓存?CacheKey怎么构成?什么时候会清除?

1、同一会话里,执行相同语句,会命中缓存;
2、CacheKey是由statementId、SQL语句、分页参数、传入参数组成,存在PerpetualCache的Map中;
3、同一会话里,执行更新语句,会清除所有一级缓存。或者select标签中flushCache=true;

2、如果跨会话场景,一级缓存会导致什么问题?

会话A读取了一级缓存数据,会话B修改该条数据。会话A不会感知,依然会从一级缓存中取,拿到过时数据。
一级缓存不能跨会话共享。

总结:如果在多个会话或分布式环境下,会有查到过时数据的问题

二级缓存

解决一级缓存不能跨会话共享的问题,范围是 namesapce 级别,可以被多个Sqlsession共享。

应用端必须要开启 cacheEnabled=true,Mapper.xml显示配置<cache/>标签,才能使用二级缓存生效。

如果只配置了cacheEnabled=true,会对执行器进行包装为CachingExecutor;<cache/>配置决定是否从缓存查询、存储;select标签上的 useCache 属性决定是否使用缓存。

1、为什么事务不提交,二级缓存不生效

二级缓存使用 TransactionalCacheManager (TCM) 来管理,调用了 TransactionalCache 的getObject\putObject\commit方法。

而TransactionalCache 里又持有了真正的 Cache对象,比较经过层层装饰的PerpetualCache。

2、为什么增删改操作会清空二级缓存

在update时,会将二级缓存队列清;commit提交时,会将二级缓存清空

public int update(MappedStatement ms, Object parameterObject) throws SQLException {
    flushCacheIfRequired(ms);
    return delegate.update(ms, parameterObject);
}

private void flushCacheIfRequired(MappedStatement ms) {
    Cache cache = ms.getCache();
    if (cache != null && ms.isFlushCacheRequired()) {
    	tcm.clear(cache);
    }
}

3、什么场景下开启二级缓存?

适合在查询为主的场景,比如历史交易、历史订单的查询。如果增删改比较频繁,二级缓存也就失去了意义

4、如何让多个Mapper共享一个二级缓存?

跨 namesapce 的缓存共享问题,可以使用 来解决

<cache-ref namesapce="com.gupaoedu.mapper.BlogMapper"/>

源码解读

    private SqlSessionFactory sqlSessionFactory;

    @Before

    public void prepare() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }
    
   /**
     * 通过 SqlSession.getMapper(XXXMapper.class)  接口方式
     * @throws IOException
     */
    @Test
    public void testSelect() throws IOException {
        SqlSession session = sqlSessionFactory.openSession();
        try {
            BlogMapper mapper = session.getMapper(BlogMapper.class);
            Blog blog = mapper.selectBlogById(1);
            session.commit();
            mapper.selectBlogById(1);
            System.out.println(blog);
        } finally {
            session.close();
        }
    }

SqlSessionFactoryBuild 执行类图

https://www.processon.com/view/link/60402d9d5653bb6efa49f324

SqlSessionFactory 执行类图

https://www.processon.com/view/link/60402dd807912951ff2f3b46

SqlSession

https://www.processon.com/view/link/60402df8f346fb55c9ad7be4

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

子津

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值