工作中redis常用的5种场景

在日常开发工作中,Redis作为一款高性能的内存数据库,凭借其强大的功能特性和卓越的性能表现,已经成为了许多项目中不可或缺的组件。本文将详细介绍Redis在实际工作中最常见的5种应用场景,并附上具体的代码实现。

1. 缓存热点数据

在高并发系统中,大量的数据库查询会对系统性能造成严重影响。通过Redis缓存热点数据,可以显著减少数据库的访问压力,提升系统响应速度。

实现示例:

public class ProductService {    @Autowired    private RedisTemplate<String, Product> redisTemplate;    @Autowired    private ProductMapper productMapper;        private static final String PRODUCT_KEY_PREFIX = "product:";    private static final long CACHE_TIMEOUT = 3600; // 缓存过期时间:1小时        public Product getProduct(Long productId) {        // 构建Redis键        String redisKey = PRODUCT_KEY_PREFIX + productId;                // 首先从Redis中查询        Product product = redisTemplate.opsForValue().get(redisKey);                if (product != null) {            // 缓存命中,直接返回            return product;        }                // 缓存未命中,查询数据库        product = productMapper.selectById(productId);                if (product != null) {            // 将查询结果存入Redis            redisTemplate.opsForValue().set(redisKey, product, CACHE_TIMEOUT, TimeUnit.SECONDS);        }                return product;    }}

2. 分布式锁

在分布式系统中,常常需要控制对共享资源的访问。Redis的SETNX命令提供了一种实现分布式锁的简单方法。

实现示例:

​​​​​​​

public class RedisLock {    @Autowired    private StringRedisTemplate redisTemplate;        private static final long LOCK_TIMEOUT = 10000; // 锁超时时间:10秒        public boolean acquireLock(String lockKey, String requestId) {        // 使用SETNX命令尝试获取锁        Boolean isLocked = redisTemplate.opsForValue().setIfAbsent(            lockKey,             requestId,            LOCK_TIMEOUT,            TimeUnit.MILLISECONDS        );                return Boolean.TRUE.equals(isLocked);    }        public boolean releaseLock(String lockKey, String requestId) {        // 使用Lua脚本确保原子性操作        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then "                     + "return redis.call('del', KEYS[1]) "                     + "else "                     + "return 0 "                     + "end";                             Long result = redisTemplate.execute(            new DefaultRedisScript<>(script, Long.class),            Collections.singletonList(lockKey),            requestId        );                return Long.valueOf(1).equals(result);    }}

3. 计数器和限流器

Redis的INCR命令可以原子性地实现计数器功能,非常适合用于实现访问统计和接口限流。

实现示例:​​​​​​​

public class RateLimiter {    @Autowired    private StringRedisTemplate redisTemplate;        private static final String RATE_LIMIT_PREFIX = "rate:limit:";    private static final int MAX_REQUESTS = 100; // 每分钟最大请求次数        public boolean isAllowed(String userId) {        String key = RATE_LIMIT_PREFIX + userId;                // 获取当前时间的分钟数作为窗口        long currentMinute = System.currentTimeMillis() / (60 * 1000);        String windowKey = key + ":" + currentMinute;                // 原子性增加计数        Long count = redisTemplate.opsForValue().increment(windowKey);                if (count == 1) {            // 设置过期时间为1分钟            redisTemplate.expire(windowKey, 60, TimeUnit.SECONDS);        }                // 判断是否超过限制        return count <= MAX_REQUESTS;    }}

4. 消息队列

虽然Redis不是专门的消息队列系统,但它的List数据结构配合LPUSH和BRPOP命令可以实现简单的消息队列功能。

实现示例:​​​​​​​

public class RedisMessageQueue {    @Autowired    private StringRedisTemplate redisTemplate;        private static final String QUEUE_KEY = "message:queue";        // 生产者    public void sendMessage(String message) {        redisTemplate.opsForList().leftPush(QUEUE_KEY, message);    }        // 消费者    @Async    public void consumeMessage() {        while (true) {            try {                // 阻塞式获取消息                List<String> message = redisTemplate.opsForList().rightPop(                    QUEUE_KEY,                    30,                    TimeUnit.SECONDS                );                                if (message != null) {                    // 处理消息                    processMessage(message);                }            } catch (Exception e) {                log.error("处理消息出错", e);            }        }    }        private void processMessage(List<String> message) {        // 具体的消息处理逻辑    }}

5. 会话管理

Redis的Hash数据结构非常适合存储用户会话信息,支持部分字段的更新,且可以设置过期时间。

实现示例:​​​​​​​

public class SessionManager {    @Autowired    private StringRedisTemplate redisTemplate;        private static final String SESSION_KEY_PREFIX = "session:";    private static final long SESSION_TIMEOUT = 1800; // 会话超时时间:30分钟        public void saveSession(String sessionId, Map<String, String> sessionData) {        String key = SESSION_KEY_PREFIX + sessionId;                // 使用Hash结构存储会话数据        redisTemplate.opsForHash().putAll(key, sessionData);                // 设置过期时间        redisTemplate.expire(key, SESSION_TIMEOUT, TimeUnit.SECONDS);    }        public void updateSessionField(String sessionId, String field, String value) {        String key = SESSION_KEY_PREFIX + sessionId;                // 更新单个字段        redisTemplate.opsForHash().put(key, field, value);                // 刷新过期时间        redisTemplate.expire(key, SESSION_TIMEOUT, TimeUnit.SECONDS);    }        public Map<Object, Object> getSession(String sessionId) {        String key = SESSION_KEY_PREFIX + sessionId;        return redisTemplate.opsForHash().entries(key);    }        public void deleteSession(String sessionId) {        String key = SESSION_KEY_PREFIX + sessionId;        redisTemplate.delete(key);    }}

总结

Redis凭借其出色的性能和丰富的数据结构,在实际工作中可以解决很多具体问题。上述5种场景只是Redis应用的冰山一角,在实际开发中,我们还可以根据具体需求,结合Redis的特性来设计更多的解决方案。

在使用Redis时,需要注意以下几点:

  1. 合理设置过期时间,避免内存占用过大

  2. 注意缓存与数据库的一致性问题

  3. 在分布式环境下要考虑并发问题

  4. 根据实际需求选择合适的数据结构

  5. 定期监控Redis的内存使用情况和性能指标

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/67526.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LLM - 大模型 ScallingLaws 的迁移学习与混合训练(PLM) 教程(3)

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/145212097 免责声明&#xff1a;本文来源于个人知识与公开资料&#xff0c;仅用于学术交流&#xff0c;欢迎讨论&#xff0c;不支持转载。 Scalin…

深入浅出 Go语言并发安全字典 sync.Map:原理、使用与优化

深入浅出 Go语言并发安全字典 sync.Map:原理、使用与优化 背景介绍 Go语言作为一种高效的并发编程语言,其标准库中提供了丰富的并发工具,如sync.WaitGroup、sync.Mutex等。然而,在实际开发中,我们经常需要在多个goroutine之间共享数据,这就涉及到并发安全的问题。传统的…

解决leetcode第3418题机器人可以获得的最大金币数

3418.机器人可以获得的最大金币数 难度&#xff1a;中等 问题描述&#xff1a; 给你一个mxn的网格。一个机器人从网格的左上角(0,0)出发&#xff0c;目标是到达网格的右下角(m-1,n-1)。在任意时刻&#xff0c;机器人只能向右或向下移动。 网格中的每个单元格包含一个值coin…

蓝桥杯 Python 组知识点容斥原理

容斥原理 这张图初中或者高中数学课应该画过 也就是通过这个简单的例子引出容斥原理的公式 这张图的面积&#xff1a;s1 s3 s7 - 2 * s2 - 2 * s4 - 2 * s6 3 * s5 通过此引导出容斥原理公式 那么下面来一起看看题目 题目描述 给定 n,m 请求出所有 n 位十进制整数中有多…

GitLab:添加SSH密钥之前,您不能通过SSH来拉取或推送项目代码

1、查看服务器是否配置过 [rootkingbal-ecs-7612 ~]# cd .ssh/ [rootkingbal-ecs-7612 .ssh]# ls authorized_keys id_ed25519 id_ed25519.pub id_rsa id_rsa.pub2、创建密钥 $ ssh-keygen -t rsa -C kingbalkingbal.com # -C 后写你的邮箱 一路回车 3、复制密钥 [rootk…

Rust:指针 `*T` 和引用 `T`的区别

在 Rust 编程语言中&#xff0c;*T 和 &T 是两种不同类型的指针&#xff0c;它们各自代表了不同的内存访问方式和所有权模型。 *T&#xff08;原始指针或裸指针&#xff09;&#xff1a; *T 是一个原始指针&#xff08;也称为裸指针或裸引用&#xff09;&#xff0c;它可以…

day10_Structured Steaming

文章目录 Structured Steaming一、结构化流介绍&#xff08;了解&#xff09;1、有界和无界数据2、基本介绍3、使用三大步骤(掌握)4.回顾sparkSQL的词频统计案例 二、结构化流的编程模型&#xff08;掌握&#xff09;1、数据结构2、读取数据源2.1 File Source2.2 Socket Source…

华为OD机试E卷 ---最大值

一、题目描述 给定一组整数(非负)&#xff0c;重排顺序后输出一个最大的整数。 二、示例1 用例1 输入 10 9输出 910说明:输出结果可能非常大&#xff0c;所以你需要返回一个 字符串只而不是整数。 三、输入描述 数字组合 四、输出描述 最大的整数 五、解题思路 字符…

Elasticsearch容器启动报错:AccessDeniedException[/usr/share/elasticsearch/data/nodes];

AccessDeniedException 表明 Elasticsearch 容器无法访问或写入数据目录 /usr/share/elasticsearch/data/nodes。这是一个权限问题。 问题原因&#xff1a; 1、宿主机目录权限不足&#xff1a;映射到容器的数据目录 /data/es/data 在宿主机上可能没有足够的权限供容器访问。 …

设计模式-结构型-装饰器模式

装饰器模式&#xff08;Decorator Pattern&#xff09;是结构型设计模式中的一种&#xff0c;它允许你通过将对象封装在一个新的对象中&#xff0c;来动态地添加新的功能&#xff0c;而无需改变原对象的结构。装饰器模式的核心思想是“将功能附加到对象上”&#xff0c;它是一种…

第8篇:从入门到精通:掌握Python异常处理

第8篇&#xff1a;异常处理 内容简介 本篇文章将深入探讨Python中的异常处理机制。您将学习异常的基本概念与类型&#xff0c;掌握使用try-except块处理异常的方法&#xff0c;了解finally语句的作用&#xff0c;以及如何抛出和定义自定义异常。通过丰富的代码示例&#xff0…

Ubuntu20.4和docker终端指令、安装Go环境、安装搜狗输入法、安装WPS2019:保姆级图文详解

目录 前言1、docker、node、curl版本查看终端命令1.1、查看docker版本1.2、查看node.js版本1.3、查看curl版本1.4、Ubuntu安装curl1.5、Ubuntu终端保存命令 2、安装docker-compose、Go语言2.1、安装docker-compose2.2、go语言安装步骤2.3、git版本查看 3、Ubuntu20.4安装搜狗输…

【PHP】双方接口通信校验服务

请求方 使用 ApiAuthService::buildUrl($domain, [terminal > 1, ts > time()]); //http://域名/adminapi/login/platformLogin?signF7FE8A150DEC18BE8A71C5059742C81A&terminal1&ts1736904841接收方 $getParams $this->request->get();$validate ApiA…

【设计模式】 单例模式(单例模式哪几种实现,如何保证线程安全,反射破坏单例模式)

单例模式 作用&#xff1a;单例模式的核心是保证一个类只有一个实例&#xff0c;并且提供一个访问实例的全局访问点。 实现方式优缺点饿汉式线程安全&#xff0c;调用效率高 &#xff0c;但是不能延迟加载懒汉式线程安全&#xff0c;调用效率不高&#xff0c;能延迟加载双重检…

无公网IP 实现外网访问本地 Docker 部署 Navidrome

Navidrome 是一款可以在 macOS、Linux、Windows以及 Docker 等平台上运行的跨平台开源音乐服务器应用&#xff0c;它支持传输常见的 MP3、FLAC、WAV等音频格式。允许用户通过 Web 界面或 API 进行音乐库的管理和访问。本文就介绍如何快速在 Linux 系统使用 Docker 进行本地部署…

从零开始,掌握Django Web开发

1. Django简介 Django是一个强大的Python Web框架,它使开发人员能够快速构建安全、可扩展的Web应用程序。让我们深入了解Django的特性和优势。 1.1 什么是Django? Django是一个高级Python Web框架,于2005年首次发布。它由新闻网站的开发人员创建,旨在处理快节奏的新闻编辑室…

解决conda create速度过慢的问题

问题 构建了docker容器 想在容器中创建conda环境&#xff0c;但是conda create的时候速度一直很慢 解决办法 宿主机安装的是anaconda 能正常conda create,容器里安装的是miniforge conda create的时候速度一直很慢&#xff0c;因为容器和宿主机共享网络了&#xff0c;宿主机…

【Hive】新增字段(column)后,旧分区无法更新数据问题

TOC 【一】问题描述 Hive修改数据表结构的需求&#xff0c;比如&#xff1a;增加一个新字段。 如果使用如下语句新增列&#xff0c;可以成功添加列col1。但如果数据表tb已经有旧的分区&#xff08;例如&#xff1a;dt20190101&#xff09;&#xff0c;则该旧分区中的col1将为…

【Python】Selenium根据网页页面长度,模拟向下滚动鼠标,直到网页底部的操作

最近在弄selenium的爬取的过程中&#xff0c;我发现一些网站上的表格&#xff0c;是需要手动拉到底部才能加载完成的。 如果没有拉到底部&#xff0c;那么在获取网页表格的时候&#xff0c;表格就会只有显示的一部分&#xff0c;页面就不完整。 所以我就整理了一些模拟滚动鼠…

openharmony电源管理子系统

电源管理子系统 简介目录使用说明相关仓 简介 电源管理子系统提供如下功能&#xff1a; 重启服务&#xff1a;系统重启和下电。系统电源管理服务&#xff1a;系统电源状态管理和休眠运行锁管理。显示相关的能耗调节&#xff1a;包括根据环境光调节背光亮度&#xff0c;和根…