为什么建议框架源码学习从Mybatis开始(中)

简介: 为什么建议框架源码学习从Mybatis开始(中)

2、MapperProxy:就是上面创建代理时的增强

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      } else if (isDefaultMethod(method)) {
        return invokeDefaultMethod(proxy, method, args);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
   --------------------------
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    return mapperMethod.execute(sqlSession, args);
}


针对非默认,非Object方法(也就是我们的业务方法),会封装成一个MapperMethod, 调

用的是MapperMethod.execute

3、MapperMethod

一个业务方法在执行时,会被封装成MapperMethod, MapperMethod 执行时,又会去调用了Sqlsession

public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    switch (command.getType()) {
      case SELECT:
        ...
        result = sqlSession.selectOne(command.getName(), param);
        ...
        break;
      ....
}

绕了一周,终究回到了最基本的调用方式上。

result = sqlSession.selectOne(command.getName(), param);
User user = sqlSession.selectOne("com.wqd.dao.UserMapper.getById", 1);

总结下:

  • 最基本用法=sqlsession.selectOne(statement.id,参数)
  • Mapper=User代理类getById---》MapperProxy.invoke方法---》MapperMethod.execute()---》sqlsession.selectOne(statement.id,参数)

显然这一绕,方便了开发人员,但是对于系统来说带来的是多余开销。


五、缓存


Mybatis 还加入了缓存的设计。

分为一级缓存和二级缓存


1.一级缓存

先看长什么样子?原来就是HashMap的封装

public class PerpetualCache implements Cache {
  private String id;
  private Map<Object, Object> cache = new HashMap<Object, Object>();
  public PerpetualCache(String id) {
    this.id = id;
  }
}

在什么位置?作为BaseExecutor的一个属性存在。

public abstract class BaseExecutor implements Executor {
 protected BaseExecutor(Configuration configuration, Transaction transaction) {
    this.localCache = new PerpetualCache("LocalCache");
 }
}

Executor上面说过,Sqlsession的能力其实是委托Executor完成的.Executor作为Sqlsession的一个属性存在。

所以:MyBatis一级缓存的生命周期和SqlSession一致


2.二级缓存

2.1基本信息

二级缓存在设计上相对与一级缓存就比较复杂了。

以xml配置为例,二级缓存需要配置开启,并配置到需要用到的namespace中。

<setting name="cacheEnabled" value="true"/>
<mapper namespace="mapper.StudentMapper">
    <cache/>
</mapper>


同一个namespace下的所有MappedStatement共用同一个二级缓存。二级缓存的生命周期跟随整个应用的生命周期,同时二级缓存也实现了同namespaceSqlSession数据的共享。


二级缓存配置开启后,其数据结构默认也是PerpetualCache。这个和一级缓存的一样。


但是在构建二级缓存时,mybatis使用了一个典型的设计模式装饰模式,对PerpetualCache进行了一层层的增强,使得二级缓存成为一个被层层装饰过的PerpetualCache,每装饰一层,就有不同的能力,这样一来,二级缓存就比一级缓存丰富多了。

装饰类有:

  • LoggingCache:日志功能,装饰类,用于记录缓存的命中率,如果开启了DEBUG模式,则会输出命中率日志
  • LruCache:采用了Lru算法的Cache实现,移除最近最少使用的Key/Value
  • ScheduledCache: 使其具有定时清除能力
  • BlockingCache: 使其具有阻塞能力
层层装饰
private Cache setStandardDecorators(Cache cache) {
    try {
      MetaObject metaCache = SystemMetaObject.forObject(cache);
      if (size != null && metaCache.hasSetter("size")) {
        metaCache.setValue("size", size);
      }
      if (clearInterval != null) {
        cache = new ScheduledCache(cache);
        ((ScheduledCache) cache).setClearInterval(clearInterval);
      }
      if (readWrite) {
        cache = new SerializedCache(cache);
      }
      cache = new LoggingCache(cache);
      cache = new SynchronizedCache(cache);
      if (blocking) {
        cache = new BlockingCache(cache);
      }
      return cache;
    } catch (Exception e) {
      throw new CacheException("Error building standard cache decorators.  Cause: " + e, e);
    }
  }


2.2如何工作

二级缓存的工作原理,还是用到装饰模式,不过这次装饰的Executor。使用CachingExecutor去装饰执行SQL的Executor

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    executorType = executorType == null ? defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    Executor executor;
    if (ExecutorType.BATCH == executorType) {
      executor = new BatchExecutor(this, transaction);
    } else if (ExecutorType.REUSE == executorType) {
      executor = new ReuseExecutor(this, transaction);
    } else {
      executor = new SimpleExecutor(this, transaction);
    }
    if (cacheEnabled) {
      executor = new CachingExecutor(executor);//装饰
    }
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
  }

当执行查询时,先从二级缓存中查询,二级缓存没有时才去走Executor的查询


相关文章
|
4月前
|
SQL XML Java
mybatis-源码深入分析(一)
mybatis-源码深入分析(一)
|
13天前
|
缓存 NoSQL Java
Mybatis学习:Mybatis缓存配置
MyBatis缓存配置包括一级缓存(事务级)、二级缓存(应用级)和三级缓存(如Redis,跨JVM)。一级缓存自动启用,二级缓存需在`mybatis-config.xml`中开启并配置映射文件或注解。集成Redis缓存时,需添加依赖、配置Redis参数并在映射文件中指定缓存类型。适用于查询为主的场景,减少增删改操作,适合单表操作且表间关联较少的业务。
|
2月前
|
SQL Java 数据库连接
持久层框架MyBatisPlus
持久层框架MyBatisPlus
61 1
持久层框架MyBatisPlus
|
3月前
|
Java 关系型数据库 MySQL
springboot学习五:springboot整合Mybatis 连接 mysql数据库
这篇文章是关于如何使用Spring Boot整合MyBatis来连接MySQL数据库,并进行基本的增删改查操作的教程。
481 0
springboot学习五:springboot整合Mybatis 连接 mysql数据库
|
3月前
|
前端开发 Java 数据库连接
表白墙/留言墙 —— 中级SpringBoot项目,MyBatis技术栈MySQL数据库开发,练手项目前后端开发(带完整源码) 全方位全步骤手把手教学
本文是一份全面的表白墙/留言墙项目教程,使用SpringBoot + MyBatis技术栈和MySQL数据库开发,涵盖了项目前后端开发、数据库配置、代码实现和运行的详细步骤。
97 0
表白墙/留言墙 —— 中级SpringBoot项目,MyBatis技术栈MySQL数据库开发,练手项目前后端开发(带完整源码) 全方位全步骤手把手教学
|
3月前
|
Java 数据库连接 mybatis
Springboot整合Mybatis,MybatisPlus源码分析,自动装配实现包扫描源码
该文档详细介绍了如何在Springboot Web项目中整合Mybatis,包括添加依赖、使用`@MapperScan`注解配置包扫描路径等步骤。若未使用`@MapperScan`,系统会自动扫描加了`@Mapper`注解的接口;若使用了`@MapperScan`,则按指定路径扫描。文档还深入分析了相关源码,解释了不同情况下的扫描逻辑与优先级,帮助理解Mybatis在Springboot项目中的自动配置机制。
228 0
Springboot整合Mybatis,MybatisPlus源码分析,自动装配实现包扫描源码
|
3月前
|
缓存 Cloud Native 安全
探索阿里巴巴新型ORM框架:超越MybatisPlus?
【10月更文挑战第9天】在Java开发领域,Mybatis及其增强工具MybatisPlus长期占据着ORM(对象关系映射)技术的主导地位。然而,随着技术的发展,阿里巴巴集团推出了一种新型ORM框架,旨在提供更高效、更简洁的开发体验。本文将对这一新型ORM框架进行探索,分析其特性,并与MybatisPlus进行比较。
126 0
|
4月前
|
Java 关系型数据库 数据库连接
mybatis-plus学习
MyBatis-Plus ,MyBatis 最佳搭档,只做增强不做改变,为简化开发、提高效率而生。
59 5
|
5月前
|
XML Java 数据库连接
mybatis源码研究、搭建mybatis源码运行的环境
这篇文章详细介绍了如何搭建MyBatis源码运行的环境,包括创建Maven项目、导入源码、添加代码、Debug运行研究源码,并提供了解决常见问题的方法和链接到搭建好的环境。
mybatis源码研究、搭建mybatis源码运行的环境
|
5月前
|
Java 数据库连接 Spring
后端框架入门超详细 三部曲 Spring 、SpringMVC、Mybatis、SSM框架整合案例 【爆肝整理五万字】
文章是关于Spring、SpringMVC、Mybatis三个后端框架的超详细入门教程,包括基础知识讲解、代码案例及SSM框架整合的实战应用,旨在帮助读者全面理解并掌握这些框架的使用。
后端框架入门超详细 三部曲 Spring 、SpringMVC、Mybatis、SSM框架整合案例 【爆肝整理五万字】