为什么建议框架源码学习从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的查询


相关文章
|
19天前
|
SQL Java 关系型数据库
Java中的ORM框架——myBatis
Java中的ORM框架——myBatis
|
4天前
|
Java 数据库连接 Spring
Spring 整合 MyBatis 底层源码解析
Spring 整合 MyBatis 底层源码解析
|
7天前
|
Java 关系型数据库 MySQL
Mybatis入门之在基于Springboot的框架下拿到MySQL中数据
Mybatis入门之在基于Springboot的框架下拿到MySQL中数据
15 4
|
7天前
|
SQL Java 数据库连接
2万字实操案例之在Springboot框架下基于注解用Mybatis开发实现基础操作MySQL之预编译SQL主键返回增删改查
2万字实操案例之在Springboot框架下基于注解用Mybatis开发实现基础操作MySQL之预编译SQL主键返回增删改查
16 2
|
9天前
|
SQL XML Java
【MyBatis】 MyBatis框架下的高效数据操作:深入理解增删查改(CRUD)
【MyBatis】 MyBatis框架下的高效数据操作:深入理解增删查改(CRUD)
11 1
|
17天前
|
Java 数据库连接 Android开发
SSM框架——使用MyBatis Generator自动创建代码
SSM框架——使用MyBatis Generator自动创建代码
18 2
|
3天前
|
SQL 缓存 Java
Java框架之MyBatis 07-动态SQL-缓存机制-逆向工程-分页插件
Java框架之MyBatis 07-动态SQL-缓存机制-逆向工程-分页插件
|
6天前
|
XML Java 数据库连接
浅谈后端boot框架整合第三方技术JUnit MyBatis Druid整体思想
浅谈后端boot框架整合第三方技术JUnit MyBatis Druid整体思想
8 0
|
10天前
|
Java 数据库连接 Maven
Mybatis学习
Mybatis学习
10 0
|
2月前
|
XML Java 数据库连接
利用MyBatis框架操作数据库2
利用MyBatis框架操作数据库
25 2