首页 > 数据库 >实现concurrentHashMap与redis两级缓存

实现concurrentHashMap与redis两级缓存

时间:2023-07-16 10:35:35浏览次数:39  
标签:concurrentHashMap 缓存 Redis redis key import data localCache

一、 实现concurrentHashMap与redis两级缓存

以下是一种使用ConcurrentHashMap和Redis实现两级缓存的示例代码:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;

import java.util.concurrent.ConcurrentHashMap;

@Service
public class TwoLevelCacheService {
    private ConcurrentHashMap<String, Object> localCache = new ConcurrentHashMap<>();
    private static final String REDIS_CACHE_PREFIX = "mycache:";

    @Autowired
    private Jedis jedis;

    @Cacheable(value = "mycache", key = "#key")
    public Object getData(String key) {
        if (localCache.containsKey(key)) {
            return localCache.get(key);
        } else {
            Object data = jedis.get(REDIS_CACHE_PREFIX + key);
            if (data != null) {
                localCache.put(key, data);
            }
            return data;
        }
    }

    @CacheEvict(value = "mycache", key = "#key")
    public void clearCache(String key) {
        localCache.remove(key);
        jedis.del(REDIS_CACHE_PREFIX + key);
    }

    // Example method for adding/updating data in cache
    public void putData(String key, Object data) {
        localCache.put(key, data);
        jedis.set(REDIS_CACHE_PREFIX + key, data.toString());
    }
}

  

在上述示例中,TwoLevelCacheService类是一个实现了两级缓存的服务类。它使用了Spring的缓存注解@Cacheable和@CacheEvict来标记方法的缓存行为。

localCache是一个ConcurrentHashMap用于实现内存级别的缓存,而jedis对象是通过Spring的依赖注入来获取的用于操作Redis。

getData方法首先在本地缓存(localCache)中查找数据,如果数据不存在,则从Redis中获取,并将其存储到本地缓存以供下次使用。

clearCache方法用于除本地缓存和Redis中的缓存数据。

putData`方法示范了如何将数据添加其中数据会被存储在本地缓存和Redis中。

请注意,以上示例仅为演示目的,并可能需要根据实际需求进行适当的修改和调整。另外,确保已正确配置和初始化Redis连接,以及已启用Spring的缓存功能。

二、 实现分布式架构concurrentHashMap与redis两级缓存

 

在分布式架构中,使用ConcurrentHashMap和Redis实现两级缓存需要考虑多个节点之间的数据一致性和并发访问问题。以下是一种基于分布式锁实现的示例代码:

import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
@Service
public class DistributedCacheService {
    private ConcurrentHashMap<String, Object> localCache = new ConcurrentHashMap<>();
    @Autowired
    private RedissonClient redissonClient;
    public Object getData(String key) {
        if (localCache.containsKey(key)) {
            return localCache.get(key);
        } else {
            Lock lock = redissonClient.get(key);
            lock.lock();
            try {
                // Double-checked locking to prevent multiple threads refreshing the cache simultaneously
                if (localCache.containsKey(key)) {
                    return localCache.get(key);
                } else {
                    // Get data from Redis
                    RBucket<Object> bucket = redissonClient.getBucket(key);
                    Object data = bucket.get();
                    if (data != null) {
                        localCache.put(key, data);
                    }
                    return data;
                }
            } finally {
                lock.unlock();
            }
        }
    }

    public void putData(String key, Object data) {
        RBucket<Object> bucket = redissonClient.getBucket(key);
        bucket.set(data);
        localCache.put(key, data);
    }

    public void evictData(String key) {
        RBucket<Object> bucket = redissonClient.getBucket(key);
        bucket.delete();
        localCache.remove(key);
    }
}

  

在上述示例中,使用了Redisson作为Redis客户端库来实现分布式锁。DistributedCacheService类使用了基于双重检查锁定模式,以确保多个节点之间的数据一致性。

在getData方法中,首先在本地缓存(localCache)中检查数据,如果数据不存在,则获取一个Redisson分布式锁并进行加锁操作。进入加锁代码块后,再次检查本地缓存是否有数据,以防止其他线程在等待锁的过程中已经加载了数据。如果本地缓存依然没有数据,则从Redis中获取数据,并将其存储到本地缓存中。最后,在退出加锁代码块之前释放分布式锁。

putData方法用于存储数据,通过Redisson的RBucket对象将数据存储到Redis中,并同时更新本地缓存。

evictData方法用于清除数据,删除Redis中对应的数据并从本地缓存中移除。

请注意,上述示例中的分布式锁实现是基于Redisson的Redis分布式锁,你也可以选择其他基于Redis的分布式锁实现方式。此外,确保已正确配置和初始化Redis连接和Redisson客户端。

标签:concurrentHashMap,缓存,Redis,redis,key,import,data,localCache
From: https://www.cnblogs.com/baicaowei/p/17557533.html

相关文章

  • JAVA面试题----Redis
    Redisredis快的原因:完全基于内存操作,请求都在内存中所以快;它是单线程,省去了线程切换的时间和锁竞争的开销。采用io多路复用,多路指多个网络,对单个线程进行复用,避免了大量无用的操作。为什么使用redis:速度快,支持丰富的数据类型,redis集群不支持事务,内部单节点支持事务,操作都是原子......
  • Redis与Memcached有什么区别?
    Memcached与Redis有什么区别Redis和Memcached都是基于内存的数据存储系统,Memacched是高性能分布式内存缓存服务,其本质傻姑娘就是一个内存key-value数据库。Redis是一个开源的key-value存储系统,与Memcached类似,Redis将大部分数据存储在内存中,支持的数据类型,字符串,hash表,链表,集合,......
  • 如何使用C#中的Lambda表达式操作Redis Hash结构,简化缓存中对象属性的读写操作
    Redis是一个开源的、高性能的、基于内存的键值数据库,它支持多种数据结构,如字符串、列表、集合、散列、有序集合等。其中,Redis的散列(Hash)结构是一个常用的结构,今天跟大家分享一个我的日常操作,如何使用Redis的散列(Hash)结构来缓存和查询对象的属性值,以及如何用Lambda表达式树来简化......
  • 如何提高缓存命中率
    这种问题的话,肯定是要提前设置好缓存的第二要有相对严格的双写一致策略,只要数据库数据发生变化,就要主动更新缓存,可以用binlog,代码层面可以用读写锁限制写的请求第三要使用定时任务固定刷新第四要有判空操作,一般的缓存使用,如果不存在的key,可能会前往db进行查询,可以打破这一规则,......
  • HashMap和ConcurrentHashMap
    HashMap结构桶数组+单链表+红黑树(JDK1.8引入)容量是2的幂的原因寻找位置时,(n-1)&hashCode值等价于hash%n,但是&比%具有更高的效率。得到key的hashCode值后,通过二次hash(第一次hash时右移16位,hashCode值高16位与低16位异或操作,高16位保持不变;第二次hash时(n-1)&hashCode值)来......
  • 67.requireJS的核心原理是什么(如何动态加载的如何避免多次加载的如何缓存的)
    67.requireJS的核心原理是什么?(如何动态加载的?如何避免多次加载的?如何缓存的?)require.js的核心原理是通过动态创建script脚本来异步引入模块,然后对每个脚本的load事件进行监听,如果每个脚本都加载完成了,再调用回调函数。详细资料可以参考:《requireJS的用法和原理分析》......
  • 122.get和post请求在缓存方面的区别
    122.get和post请求在缓存方面的区别相关知识点:get请求类似于查找的过程,用户获取数据,可以不用每次都与数据库连接,所以可以使用缓存。post不同,post做的一般是修改和删除的工作,所以必须与数据库交互,所以不能使用缓存。因此get请求适合于请求缓存。回答:缓存一般只适用......
  • 【Azure Redis】Azure Redis添加了内部虚拟网络后,其他区域的主机通过虚拟网络对等互连
    问题描述跨区域无法访问AzureRedis服务,Redis启用了Network并设置在一个VNET中,现在客户端部署在另一个区域数据中心中,两个数据中心区域使用VNETPeer(对等互连)访问。但是为什么不能访问Redis服务呢? 问题解答根据AzureRedis的官方介绍,因为Redis服务使用了Azure负载均衡,并且......
  • springboot 使用caffeine 并监控本地缓存
    1、添加依赖<dependency><groupId>com.github.ben-manes.caffeine</groupId><artifactId>caffeine</artifactId></dependency> 2、添加配置packagecom.example.demo.config;importcom.github.ben......
  • caused by: io.lettuce.core.RedisCommandExecutionException: NOAUTH Authentication
    1importcom.fasterxml.jackson.annotation.JsonAutoDetect;2importcom.fasterxml.jackson.annotation.PropertyAccessor;3importcom.fasterxml.jackson.databind.DeserializationFeature;4importcom.fasterxml.jackson.databind.ObjectMapper;5importcom.f......