mybatis缓存LruCache源码分析

2024-08-21 02:58

本文主要是介绍mybatis缓存LruCache源码分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

LruCache

  • LruCache是如何实现的
  • linkedHashMap源码分析
    • 双向链表
      • 链表优点
      • 链表缺点
      • 双向链表节点
      • 移动节点到链表的尾部
    • 为什么要散列表和链表搭配使用

LruCache是如何实现的

LruCache的关键代码:

public class LruCache implements Cache {private final Cache delegate;private Map<Object, Object> keyMap;private Object eldestKey;public LruCache(Cache delegate) {this.delegate = delegate;// 设置缓存的键值对最大数量setSize(1024);}public void setSize(final int size) {/*** 重写方法:是否移除最老的链表节点,最老的链表节点就是链表的头节点*/keyMap = new LinkedHashMap<Object, Object>(size, .75F, true) {private static final long serialVersionUID = 4267176411845948333L;@Overrideprotected boolean removeEldestEntry(Map.Entry<Object, Object> eldest) {// 判断什么时候需要移除最老的节点boolean tooBig = size() > size;if (tooBig) {// 保存最老的链表节点的key,方便cycleKeyList()删除相应的keyeldestKey = eldest.getKey();}return tooBig;}};}@Overridepublic Object getObject(Object key) {// 虽然没有使用这个返回值,但是需要更细linkedHashMap的使用情况keyMap.get(key); // touchreturn delegate.getObject(key);}private void cycleKeyList(Object key) {/*** 这个方法会更新eldestKey的值* 此方法在hashMap当中,调用过程:hashmap.put()->linkedHashMap.afterNodeInsertion()->linkedHashMap.removeEldestEntry()* 最终eldestKey的值被更新*/keyMap.put(key, key);// 如果eldestKey的值被更新,则需要到真正存储缓存的地方删除键值对if (eldestKey != null) {delegate.removeObject(eldestKey);eldestKey = null;}}}

linkedHashMap源码分析

双向链表

链表优点

  1. 插入,删除,新增操作的时间复杂度都是O(1)
  2. 可以利用不连续的内存空间

链表缺点

  1. 不能随机查找,随机查找的时间复杂度是o(n)
  2. 因为要保存前后节点的引用,所以占用的内存空间会变大

双向链表节点

/*** 继承了HashMap.Node* 其实就是在hashMap节点的基础上加入before和after节点* 构成了双向链表的节点* @param <K>* @param <V>*/static class Entry<K,V> extends HashMap.Node<K,V> {Entry<K,V> before, after;Entry(int hash, K key, V value, Node<K,V> next) {super(hash, key, value, next);}}

移动节点到链表的尾部

当get()被调用了,当前节点就变成最新被访问的了,需要移动到链表的尾部

void afterNodeAccess(Node<K,V> e) { // move node to lastLinkedHashMap.Entry<K,V> last;/*** 两个判断逻辑:* 1 链表是否支持按照最近最新使用规则排序,默认按照插入顺序排序* 2 当前节点是否已经是尾节点了*/if (accessOrder && (last = tail) != e) {LinkedHashMap.Entry<K,V> p =(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;p.after = null;if (b == null) // 说明当前节点是headhead = a; //重新定义head elseb.after = a; // 重新定义p.before的指向if (a != null) a.before = b; // 重新定义p.after的指向else // a==null说明b已经是尾节点了last = b;if (last == null) // 说明当前链表为空head = p;else {   // 定义新的为节点p.before = last;last.after = p;}// 新的尾节点产生,可以看出移动链表的节点不需要通过遍历链表tail = p;++modCount;}}

为什么要散列表和链表搭配使用

针对链表不能随机访问的缺点,如果使用散列表随机访问时间复杂度为O(1)的有点,两者扬长避短,充分发挥各自的优势

这样一来,可以创建有序的map键值对

public class LinkedHashMap<K,V>extends HashMap<K,V>implements Map<K,V>

这篇关于mybatis缓存LruCache源码分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1091929

相关文章

Mybatis对MySQL if 函数的不支持问题解读

《Mybatis对MySQLif函数的不支持问题解读》接手项目后,为了实现多租户功能,引入了Mybatis-plus,发现之前运行正常的SQL语句报错,原因是Mybatis不支持MySQL的if函... 目录MyBATis对mysql if 函数的不支持问题描述经过查询网上搜索资料找到原因解决方案总结Myb

Springboot请求和响应相关注解及使用场景分析

《Springboot请求和响应相关注解及使用场景分析》本文介绍了SpringBoot中用于处理HTTP请求和构建HTTP响应的常用注解,包括@RequestMapping、@RequestParam... 目录1. 请求处理注解@RequestMapping@GetMapping, @PostMappin

mybatis-plus分表实现案例(附示例代码)

《mybatis-plus分表实现案例(附示例代码)》MyBatis-Plus是一个MyBatis的增强工具,在MyBatis的基础上只做增强不做改变,为简化开发、提高效率而生,:本文主要介绍my... 目录文档说明数据库水平分表思路1. 为什么要水平分表2. 核心设计要点3.基于数据库水平分表注意事项示例

Mybatis的mapper文件中#和$的区别示例解析

《Mybatis的mapper文件中#和$的区别示例解析》MyBatis的mapper文件中,#{}和${}是两种参数占位符,核心差异在于参数解析方式、SQL注入风险、适用场景,以下从底层原理、使用场... 目录MyBATis 中 mapper 文件里 #{} 与 ${} 的核心区别一、核心区别对比表二、底

MyBatis-Plus逻辑删除实现过程

《MyBatis-Plus逻辑删除实现过程》本文介绍了MyBatis-Plus如何实现逻辑删除功能,包括自动填充字段、配置与实现步骤、常见应用场景,并展示了如何使用remove方法进行逻辑删除,逻辑删... 目录1. 逻辑删除的必要性编程1.1 逻辑删除的定义1.2 逻辑删php除的优点1.3 适用场景2.

Spring Boot Interceptor的原理、配置、顺序控制及与Filter的关键区别对比分析

《SpringBootInterceptor的原理、配置、顺序控制及与Filter的关键区别对比分析》本文主要介绍了SpringBoot中的拦截器(Interceptor)及其与过滤器(Filt... 目录前言一、核心功能二、拦截器的实现2.1 定义自定义拦截器2.2 注册拦截器三、多拦截器的执行顺序四、过

MyBatis配置文件中最常用的设置

《MyBatis配置文件中最常用的设置》文章主要介绍了MyBatis配置的优化方法,包括引用外部的properties配置文件、配置外置以实现环境解耦、配置文件中最常用的6个核心设置以及三种常用的Ma... 目录MyBATis配置优化mybatis的配置中引用外部的propertis配置文件⚠️ 注意事项X

MyBatis中的两种参数传递类型详解(示例代码)

《MyBatis中的两种参数传递类型详解(示例代码)》文章介绍了MyBatis中传递多个参数的两种方式,使用Map和使用@Param注解或封装POJO,Map方式适用于动态、不固定的参数,但可读性和安... 目录✅ android方式一:使用Map<String, Object>✅ 方式二:使用@Param

MyBatis-Plus使用动态表名分表查询的实现

《MyBatis-Plus使用动态表名分表查询的实现》本文主要介绍了MyBatis-Plus使用动态表名分表查询,主要是动态修改表名的几种常见场景,文中通过示例代码介绍的非常详细,对大家的学习或者工作... 目录1. 引入依赖2. myBATis-plus配置3. TenantContext 类:租户上下文

C++ scoped_ptr 和 unique_ptr对比分析

《C++scoped_ptr和unique_ptr对比分析》本文介绍了C++中的`scoped_ptr`和`unique_ptr`,详细比较了它们的特性、使用场景以及现代C++推荐的使用`uni... 目录1. scoped_ptr基本特性主要特点2. unique_ptr基本用法3. 主要区别对比4. u