聊聊Mybatis的Executor之模板方法模式

举报
周杰伦本人 发表于 2022/08/30 20:19:01 2022/08/30
【摘要】 聊聊Mybatis的Executor之模板方法模式模板方法模式通过模板方法来指定流程,具体的子类来实现具体的逻辑。我们看一下Executor接口,它的实现类有BaseExecutor抽象类和CachingExecutor类 BaseExecutorBaseExecutor抽象类作为模板方法的抽象模板类,它把缓存和事务进行实现,具体变化的对数据库操作的部分由子类去实现 提交事务方法我们先说说...

聊聊Mybatis的Executor之模板方法模式

模板方法模式通过模板方法来指定流程,具体的子类来实现具体的逻辑。

我们看一下Executor接口,它的实现类有BaseExecutor抽象类和CachingExecutor类

BaseExecutor

BaseExecutor抽象类作为模板方法的抽象模板类,它把缓存和事务进行实现,具体变化的对数据库操作的部分由子类去实现

提交事务方法

我们先说说事务管理的commit()方法的实现:

@Override
  public void commit(boolean required) throws SQLException {
    if (closed) {
      throw new ExecutorException("Cannot commit, transaction is already closed");
    }
    clearLocalCache();
    flushStatements();
    if (required) {
      transaction.commit();
    }
  }
  
  1. 清除一级缓存
  2. 调用flushStatements()方法,这个方法中调用doFlushStatements抽象方法,具体操作由子类来实现,主要功能就是清除Statement对象
  3. 最后提交事务

回滚事务的逻辑和这个提交逻辑基本一致,就不再分析了

Mybatis默认开启一级缓存,是SqlSession级别的,即通过SqlSession建立会话,如果在这个会话中执行相同的sql,第一次执行的结果会进行缓存,再往后从缓存中查找

缓存数据

我们从它的query()方法来进行分析:

@Override
  public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    BoundSql boundSql = ms.getBoundSql(parameter);
    CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
    return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
  }
  1. 先通过createCacheKey()来创建CacheKey对象
  2. 根据select标签的 flushCache配置,决定在查询前是否清空缓存,将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值是false。
  3. 通过list = resultHandler == null ? (List<E>) localCache.getObject(key) : null; 这段代码可以看出先通过CacheKey对象来获取缓存,如果缓存为空的话再调用queryFromDatabase()方法从数据库中查询数据,再放入缓存中,下次使用的时候就能从缓存中取
  4. 最后遍历DeferredLoad对象集合处理嵌套查询,具体的调用deferredLoad.load(); 方法
  5. 根据setting标签的localCacheScope配置,决定缓存范围,默认值为 SESSION,会缓存一个会话中执行的所有查询。 若设置值为 STATEMENT,本地缓存将仅用于执行语句,对相同 SqlSession 的不同查询将不会进行缓存。

我们可以知道,缓存是通过HashMap来存储的,而key是CacheKey对象,影响CacheKey对象的元素有哪些呢?

    cacheKey.update(ms.getId());
    cacheKey.update(rowBounds.getOffset());
    cacheKey.update(rowBounds.getLimit());
    cacheKey.update(boundSql.getSql());

我们通过createCacheKey()中就能看出决定CacheKey对象的因素有:MappedStatement(增删改查标签节点的封装)的id,RowBounds的offset属性和limit属性,还有对应的sql语句

总结

这篇文章主要讲了Mybatis的Executor接口和它的抽象实现类BaseExecutor,BaseExecutor是抽象类,它提供了事务管理和缓存的功能,我们从query()方法分析了它的一级缓存的实现

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。