装饰器模式,感受MyBatis二级缓存的魅力

在MyBatis中对于二级缓存的设计中,我们发现使用了大量的装饰器模式,如执行器是直接查询还是进行缓存,如果缓存的话则定义缓存执行器类,二级缓存类又包装一级缓存类,事务缓存管理器包装事务缓存类,一层包装一层,最终调用到自己包装的那一层,每一层的包装都有自己的业务逻辑实现。

1. 装饰器模式介绍

这就是装饰器模式的设计理念,顾名思义,装饰器,就是装饰不同的类的功能,原有的功能还要继续使用并不影响,在原有的功能之上,去增强一些功能。

听起来很像代理模式哈,但是代理模式使用更复杂的场景,比如,我们对于日志的处理使用AOP的情况较多,一般对于这里的处理是很多的接口都会使用到它,场景不固定,而装饰器主要是继承处理,单独创建类来处理某一特定场景,场景固定,并且适合已经写好了接口功能,需要新功能进行装饰处理这样的场景。

那接下来开始吧,Mybatis有一个场景就是Sql语句的执行器,这个顾名思义,就是处理Sql语句的,最开始的设计没有二级缓存,那它就是普通的执行器,调用它的查询方法那就执行jdbc的查询操作,随着功能的优化,如果多次执行一摸一样的查询,再次去执行数据库请求则浪费性能,所以采取缓存操作,此时就需要定义装饰器模式,缓存执行器,用来包装普通查询,如果有缓存则直接从缓存查询出来,那没存储到缓存呢就调用到普通执行器进行jdbc连接查询,查询完放入缓存就完事。

所以上述所说的就是装饰器模式的设计理念。

我们来实现下代码:

2.伪代码实现

首先我们定义执行器接口,Execute,这里定义了查询方法和插入方法。

/**
 * @Author df
 * @Description: 伪代码,执行器,执行SQL的接口
 * 定义查询和新增方法。
 * @Date 2024/1/27 13:03
 */
public interface Execute {
    Object query(String id);
    void insert();
}

DefaultExecute,默认实现类,实现Execute接口,伪代码实现查询方法和插入方法,这里查询方法我就模仿查询到了一条数据并返回json数据,插入方法呢就打印语句,代表模拟执行插入语句。


/**
 * @Author df
 * @Description:执行器实现类
 * @Date 2024/1/27 13:08
 */
public class DefaultExecute implements Execute{
    @Override
    public Object query(String id) {
        System.out.println("执行查询语句");
        // 模拟假数据
        JSONObject jsonObject=new JSONObject();
        jsonObject.put("id",01);
        jsonObject.put("name","test");
        return jsonObject;
    }

    @Override
    public void insert() {
        System.out.println("执行插入语句");
    }
}

CacheExecute,缓存执行器,装饰器模式,实现Execute接口,实现query方法和insert方法,

query方法中,首先查询缓存caches变量中是否存储数据,有则从缓存变量中取出,没有则执行普通执行器执行jdbc的查询,执行完将数据存储到缓存里,这个就是缓存执行器实现的作用,

而我们缓存到普通缓存执行器中查询,用的是变量delegate,我们在构建对象时则把普通执行器(DefaultExecute)给到缓存执行器里,方便我们执行原类里的方法功能执行,这也是装饰器的精髓,可以访问到本来就应该执行到的方法delegate.query(id);,

/**
 * @Author df
 * @Description: 带缓存的执行器
 * @Date 2024/1/27 13:10
 */
public class CacheExecute implements Execute {

    // 传的是DefaultExecute
    private Execute delegate;
    private Map<String,Object> caches=new HashMap<>();

    public CacheExecute(Execute delegate){
        this.delegate=delegate;
    }

    @Override
    public Object query(String id) {
        // 从缓存中取出数据
        if (caches!=null&&caches.containsKey(id)){
            System.out.println("从缓存中取出数据");
            return caches.get(id);
        }
        Object data=delegate.query(id);
        caches.put(id,data);
        System.out.println("存储数据到缓存中");
        return data;
    }

    @Override
    public void insert() {
        delegate.insert();
    }
}

这样的示例你应该对装饰器模式有感触了,其实这样就实现了既不影响原来的方法,还可以执行到原有的方法,然后新添加一个类执行了新增的功能,这样就做到了代码的可扩展,易修改和可维护的操作。

相关推荐

  1. 装饰模式感受MyBatis二级缓存魅力

    2024-02-05 23:36:01       50 阅读
  2. MyBatis二级缓存区别

    2024-02-05 23:36:01       32 阅读
  3. springboot开启mybatis二级缓存

    2024-02-05 23:36:01       49 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-02-05 23:36:01       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-02-05 23:36:01       100 阅读
  3. 在Django里面运行非项目文件

    2024-02-05 23:36:01       82 阅读
  4. Python语言-面向对象

    2024-02-05 23:36:01       91 阅读

热门阅读

  1. 从零学算法162

    2024-02-05 23:36:01       50 阅读
  2. 【从浅到深的算法技巧】堆的定义

    2024-02-05 23:36:01       35 阅读
  3. Python循环语句——while循环的嵌套应用

    2024-02-05 23:36:01       39 阅读
  4. Spring设计模式之工厂方法

    2024-02-05 23:36:01       54 阅读
  5. 游戏如何选择服务器

    2024-02-05 23:36:01       62 阅读
  6. Linux笔记之bash脚本中的$符号

    2024-02-05 23:36:01       45 阅读
  7. 淘客返利系统:揭秘技术背后的实现方案

    2024-02-05 23:36:01       56 阅读
  8. LeetCode--代码详解 292.Nim游戏

    2024-02-05 23:36:01       50 阅读
  9. 如何创建和使用视图?

    2024-02-05 23:36:01       54 阅读
  10. 【ASP.NET Core 基础知识】--Web API--RESTful设计原则

    2024-02-05 23:36:01       45 阅读
  11. Docker

    Docker

    2024-02-05 23:36:01      43 阅读
  12. Postgresql PostGIS扩展

    2024-02-05 23:36:01       45 阅读