深入探索Java开发世界:Redis~类型分析大揭秘

news2024/11/26 12:01:05

在这里插入图片描述

文章目录

  • 深入探索Java开发世界:Redis~类型分析大揭秘
    • 一、数据结构类型
    • 二、分布式锁类型
    • 三、事物命令类型
    • 四、事物三大特性类型

深入探索Java开发世界:Redis~类型分析大揭秘

Redis数据库基础知识,类型知识点梳理~

一、数据结构类型

Redis是一种基于内存的开源键值对存储系统,支持多种数据结构类型。

  1. String(字符串)

    • 特点:
      • 最基本的数据类型。
      • 可以存储任何形式的字符串,包括二进制数据。
      • 最大值为512MB。
    • 常用命令:
      • SET key value:设置键值。
      • GET key:获取键值。
      • INCR key / DECR key:对值进行原子递增/递减操作。
      • APPEND key value:追加字符串。
    • 使用场景:
      • 缓存:将常用的数据存储在Redis中以提高访问速度。
      • 计数器:如网站访问量统计、点赞数等。
      • 会话存储:保存用户登录状态和信息。
      • 分布式锁
  2. List(列表)

    • 特点:
      • 有序的字符串集合。
      • 可以从两端推入和弹出元素(双向链表)。
    • 常用命令:
      • LPUSH key value / RPUSH key value:从左/右插入元素。
      • LPOP key / RPOP key:从左/右弹出元素。
      • LRANGE key start stop:获取指定范围内的元素。
    • 使用场景:
      • 消息队列:实现简单的生产者 - 消费者模式。
      • 最新消息列表:如社交媒体的动态更新。
      • 任务队列:后台任务调度。
  3. Set(集合)

    • 特点:
      • 无序的字符串集合。
      • 集合中的元素是唯一的。
    • 常用命令:
      • SADD key member:添加元素。
      • SREM key member:删除元素。
      • SMEMBERS key:获取所有元素。
      • SINTER key1 key2:求交集。
      • SUNION key1 key2:求并集。
      • SDIFF key1 key2:求差集。
    • 使用场景:
      • 标签系统:如文章标签。
      • 共同好友:计算用户之间的共同好友。
      • 唯一性保证:如注册用户的唯一标识。
  4. Sorted Set(有序集合)

    • 特点:
      • 有序的元素集合,每个元素附带一个分数。
      • 元素根据分数排序。
    • 常用命令:
      • ZADD key score member:添加元素及其分数。
      • ZRANGE key start stop [WITHSCORES]:按排名获取元素。
      • ZREM key member:删除元素。
      • ZRANK key member:获取元素的排名。
    • 使用场景:
      • 排行榜:游戏积分榜、竞赛排名等。
      • 优先级队列:任务调度,根据优先级处理任务。
      • 范围查询:如获取一定范围内的高分用户。
  5. Hash(哈希表)

    • 特点:
      • 键值对集合。
      • 适合存储对象。
    • 常用命令:
      • HSET key field value:设置字段的值。
      • HGET key field:获取字段的值。
      • HGETALL key:获取所有字段和值。
      • HDEL key field:删除字段。
    • 使用场景:
      • 对象存储:存储用户信息、商品信息等。
      • 缓存对象:避免序列化和反序列化操作。
  6. HyperLogLog

    • 特点:
      • 基数估算法。
      • 用于快速估算集合的基数(不重复元素的数量)。
      • 占用内存非常小(每个HyperLogLog数据结构占用12KB内存)。
    • 常用命令:
      • PFADD key element:添加元素。
      • PFCOUNT key:返回基数估算结果。
    • 使用场景:
      • 独立总数统计:如网站的独立访客数、点击量等。
  7. Bitmap

    • 特点:
      • 位数组。
      • 用于记录布尔值(0或1)。
    • 常用命令:
      • SETBIT key offset value:设置位的值。
      • GETBIT key offset:获取位的值。
      • BITCOUNT key [start end]:统计特定位范围内1的数量。
    • 使用场景:
      • 签到系统:记录用户每日签到情况。
      • 用户在线情况:记录用户在线时长。
      • 大规模布尔值存储:如A/B测试组的分配。
  8. Geospatial(地理位置)

    • 特点:
      • 存储地理位置数据。
      • 提供半径查询、距离计算等功能。
    • 常用命令:
      • GEOADD key longitude latitude member:添加地理位置。
      • GEORADIUS key longitude latitude radius unit:查询指定半径内的成员。
      • GEODIST key member1 member2 unit:计算两个成员之间的距离。
    • 使用场景:
      • 附近的人/店:社交应用、电子商务应用的地理位置查询。
      • 路线规划:计算距离和路径优化。
  9. Streams

    • 特点:
      • 日志数据结构。
      • 支持消费组,可以实现消费者分组。
    • 常用命令:
      • XADD key * field value [field value ...]:添加日志条目。
      • XRANGE key start end:按范围获取条目。
      • XREAD COUNT count STREAMS key ID:读取新条目。
      • XGROUP CREATE key groupname id:创建消费组。
    • 使用场景:
      • 日志收集:实时日志收集和处理。
      • 消息队列:复杂的消息队列系统,支持多消费者。
      • 事件溯源:记录和回放事件。

二、分布式锁类型

使用分布式锁时,要考虑锁的超时时间、锁的可重入性、锁的安全性等方面的问题,以确保系统的正确性和性能。

Redis中的分布式锁类型

  1. 基于SETNX命令的分布式锁
    • 实现:利用Redis的原子性操作,通过SETNX命令来实现锁的获取,当某个客户端成功地将一个特定的键设置为锁时,其他客户端无法再设置该键,从而实现分布式锁的效果。
    • 优点:简单、易于实现。
    • 缺点:存在死锁问题,因为如果持有锁的客户端在执行完业务逻辑之前出现异常或者宕机,锁将永远得不到释放。
    • 解决方案
      • 引入看门狗机制:通过为获取到锁的客户端设置一个过期时间,并使用一个后台线程(即看门狗)来监控锁的状态,确保锁在业务处理完成之后能够自动释放。
      • 原理:即使持有锁的客户端异常退出或宕机,由于锁设置了过期时间并且看门狗会不断更新锁的过期时间,其他客户端在一定时间内仍然能够获取到锁。
  2. 基于Redlock算法的分布式锁
    • 实现Redlock算法是由Redis的作者提出的一种分布式锁算法,它通过在多个独立的Redis实例上加锁来实现分布式锁。
    • 具体实现过程:获取当前时间戳、尝试在多个实例上加锁、验证大多数实例是否成功加锁、如果大多数实例成功加锁则表示获取锁成功,否则表示获取失败。
    • 优点:相对较为安全,能够避免单点故障导致的死锁问题。
    • 缺点:实现相对复杂,需要确保各个Redis实例的时间同步。
  3. 使用Redisson实现分布式锁
    • 原理Redisson实现的分布式锁利用了Redis的特性,并且内置了看门狗机制,并且Redisson内部已经处理好了看门狗机制。当你获取到锁后,Redisson会启动一个后台线程,周期性地延长锁的过期时间(每隔10秒),确保锁在持有期间不会因为过期而被自动释放。这个机制有效地防止了因意外长时间持锁导致的死锁问题。
    • 实现步骤
      • 客户端尝试获取锁时,设置一个带有过期时间的键值对(即锁),并给该键设置一个适当的过期时间,一般可以使用SET key value PX milliseconds NX命令来实现。
      • 在获取锁成功后,启动一个后台线程(即看门狗),不断延长锁的过期时间以防止锁过早释放。
      • 在业务处理完成后,客户端主动释放锁,通过DEL key命令删除锁的键。
    • 实现流程

(1)引入Redisson的依赖。

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.16.3</version>
</dependency>

(2)配置Redisson客户端。

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

public class RedissonConfig {
    public static RedissonClient createClient() {
        Config config = new Config();
        config.useSingleServer().setAddress("redis://127.0.0.1:6379");
        return Redisson.create(config);
    }
}

(3)通过Redisson客户端来获取和释放分布式锁。

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;

public class DistributedLockExample {
    public static void main(String[] args) {
        RedissonClient redissonClient = RedissonConfig.createClient();

        // 获取名为 "myLock" 的锁
        RLock lock = redissonClient.getLock("myLock");

        try {
            // 尝试获取锁,等待时间为100秒,如果获取成功,则持有锁10秒
            if (lock.tryLock(100, 10, TimeUnit.SECONDS)) {
                try {
                    // 锁获取成功,执行需要加锁的业务逻辑
                    System.out.println("锁定成功,执行业务逻辑");
                } finally {
                    // 释放锁
                    lock.unlock();
                }
            } else {
                System.out.println("未能获取到锁");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            redissonClient.shutdown();
        }
    }
}

使用分布式锁场景

  • 控制对共享资源的访问:例如限制对数据库的并发访问,保证数据的一致性。
  • 防止重复操作:例如在订单支付时,需要防止用户重复支付同一笔订单。
  • 避免缓存击穿:通过加锁避免大量并发请求同时穿透缓存直接请求数据库。

三、事物命令类型

Redis中的事务是一组命令的原子性操作,可以保证这组命令要么全部执行成功,要么全部失败。Redis事务使用MULTI、EXEC、DISCARD和WATCH等命令进行控制。

Redis事务命令类型

  1. MULTI命令:开始事务。
  2. MULTI和EXEC之间:可以执行多个命令,这些命令会被放入一个队列中,而不是立即执行。
  3. EXEC命令:提交事务,Redis会按照顺序执行队列中的命令,如果所有命令都执行成功,事务成功提交;否则,事务失败。
  4. DISCARD命令:取消事务,清空事务队列中的所有命令。
  5. WATCH命令:监视一个或多个键,如果在事务执行期间被监视的键发生了变化,事务将被中断。

Redis事务使用场景

  1. 原子性操作:Redis事务可以确保一组操作的原子性,要么全部执行成功,要么全部失败回滚。这对于需要执行多个命令才能完成的操作非常有用,例如购买商品时同时减少库存、记录订单等操作可以放在一个事务中。
  2. 批量操作:Redis事务可以将多个命令一次性发送给服务器执行,减少网络延迟开销。通过将多个操作放在一个事务中,可以提高性能和效率。
  3. 乐观锁机制:通过WATCH命令和事务结合,可以实现乐观锁机制。在操作某个键之前,先通过WATCH命令监视该键,如果在执行事务期间该键的值被修改,则事务执行失败。可以利用这个特性实现乐观锁来保证并发操作的一致性。
  4. 批量写入缓存:在某些场景下,需要将多个键值对同时写入Redis缓存中,保证数据的一致性。使用事务可以将这些写入命令放入队列中,然后一次性执行,避免了在执行过程中被其他操作干扰。
  5. 实现简单的队列:通过将任务放入队列中,然后使用事务和BRPOP命令可以实现简单的队列功能。多个客户端可以并发地将任务推入队列,然后通过事务的方式一次性取出多个任务进行处理。

Redis事物使用Demo

import redis.clients.jedis.Jedis;
import redis.clients.jedis.Response;
import redis.clients.jedis.Transaction;

public class RedisTransactionExample {
    public static void main(String[] args) {
        // 使用Jedis库连接Redis服务器
        Jedis jedis = new Jedis("localhost", 6379);
        
        // 开启事务
        Transaction transaction = jedis.multi();
        
        // 将多个命令添加到事务中
        transaction.set("key1", "value1");
        transaction.set("key2", "value2");
        
        // 执行事务,并返回执行结果
        Response<String> response1 = transaction.get("key1");
        Response<String> response2 = transaction.get("key2");
        // 执行事务
        // 在事务中,命令并不会立即执行,而是放入队列中等待exec()命令执行
        transaction.exec();
        
        // 获取执行结果
        String value1 = response1.get();
        String value2 = response2.get();
        
        System.out.println("Value of key1: " + value1);
        System.out.println("Value of key2: " + value2);
        
        // 关闭连接
        jedis.close();
    }
}

**ps:**Redis事务并不是严格的ACID事务,它没有提供隔离级别和回滚日志等特性。在Redis事务中,如果某个命令执行失败,后续的命令仍然会继续执行,而不会回滚到事务开始之前的状态,对于强一致性要求较高的场景,Redis事务可能不适用。

四、事物三大特性类型

Redis事务适用于对数据一致性要求较低但需要确保操作顺序的场景。对于更复杂的事务管理和更高的数据一致性要求,可能需要考虑使用关系型数据库或其他解决方案。

  1. 单独隔离操作
    • 特性描述
      • Redis事务中的所有命令都会被依次执行,中间不会插入其他客户端的命令。
      • 这意味着在一个事务中,一系列命令要么全部执行,要么全部不执行,不存在部分执行的情况。
    • 使用场景
      • 计数器操作:确保多个增减操作在同一时间点的原子性。例如,某个文章的点赞数同时被多个用户点击时,通过事务确保计数器的正确性。
      • 集合操作:对集合进行批量操作时,确保整个操作的原子性和一致性。
    • 代码Demo
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;

public class RedisTransactionExample {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("localhost");
        
        // 开启事务
        Transaction transaction = jedis.multi();
        
        try {
            // 将多个命令打包到一个事务中
            transaction.incr("counter");
            transaction.rpush("queue", "message1");
            transaction.set("key1", "value1");

            // 执行事务
            transaction.exec();
        } catch (Exception e) {
            e.printStackTrace();
            // 处理事务执行失败的情况,放弃事务
            transaction.discard();
        } finally {
            jedis.close();
        }
    }
}
  1. 没有隔离级别的概念
    • 特性描述
      • Redis事务中的命令是按照顺序串行执行的,不存在并发访问数据的情况,因此也就不存在传统数据库中的隔离级别(如读已提交、可重复读、幻读等)。
    • 使用场景
      • 简单的读写操作:避免复杂的并发控制需求,确保单一客户端在事务期间的数据操作不被其他客户端干扰。
      • 确保顺序性:在需要严格顺序执行的操作场景下,事务提供了一种方便的实现方式。
    • 代码Demo
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;

public class RedisTransactionExample {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("localhost");
        
        // 开启事务
        Transaction transaction = jedis.multi();
        
        try {
            // 将多个命令按顺序打包到一个事务中
            transaction.set("key1", "value1");
            transaction.set("key2", "value2");
            transaction.incr("counter");

            // 执行事务
            transaction.exec();
        } catch (Exception e) {
            e.printStackTrace();
            // 处理事务执行失败的情况,放弃事务
            transaction.discard(); 
        } finally {
            jedis.close();
        }
    }
}
  1. 不保证原子性
    • 特性描述
      • 虽然Redis事务将多个命令打包成一个执行单元,但它并不完全保证原子性。
      • 如果在事务执行过程中出现了错误,事务中已执行的命令不会回滚,而是会继续执行未执行的命令。
    • 使用场景
      • 批量更新操作:在需要更新多个键值对的场景下,事务可以简化代码逻辑,尽管不能完全保证原子性,但通过合理的错误处理可以满足业务需求。
      • 数据一致性要求不高的操作:例如日志记录、缓存更新等,即使部分命令执行失败,也不会对整体系统造成巨大影响。
    • Java代码示例
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;

public class RedisTransactionExample {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("localhost");
        
        // 开启事务
        Transaction transaction = jedis.multi();
        
        try {
            // 将多个命令打包到一个事务中
            transaction.set("key1", "value1");
            transaction.incr("counter");
            
            // 故意引入错误的命令(例如对不存在的哈希字段进行递增)
            transaction.hincrBy("nonexistent_hash", "field", 1);

            // 执行事务
            transaction.exec();
        } catch (Exception e) {
            e.printStackTrace();
            // 处理事务执行失败的情况,放弃事务
            transaction.discard(); 
        } finally {
            jedis.close();
        }
    }
}

无论世界如何纷扰,心中有梦,便有了方向

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

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

相关文章

Pycharm导入内置库或者第三方库时标红,no module named ‘xxx‘

各版本的Pycharm都有可能会出现这样的问题&#xff1a;有些时候内置库和第三方库被标红为“No module named xxx”&#xff0c;而自己的库却能被正常导入。 本人是在使用远程ssh解释器时遇到的。实际运行该代码文件时&#xff0c;能够正常运行&#xff08;若不能正常运行则可能…

Stop Motion Studio Pro for Mac:Mac上的动画大师,让你的创意无限流动!

Stop Motion Studio Pro for Mac为创作者们提供了一个直观且易于使用的平台&#xff0c;让他们能够将静态的物体和场景转化为生动有趣的定格动画。&#x1f3a5; 无论是制作简单的玩具动画&#xff0c;还是复杂的电影级场景&#xff0c;这款软件都能轻松应对&#xff0c;让你的…

浅谈Mysql Innodb存储引擎

一、Mysql整体架构 二、MySQL 5.7 支持的存储引擎 类型 描述 MyISAM 拥有较高的插入、查询速度&#xff0c;但不支持事务 InnoDB 5.5版本后Mysql的默认数据库&#xff0c;5.6版本后支持全文索引&#xff0c;事务型数据库的首选引擎&#xff0c;支持ACID事务&#xff0c;支…

真正的智慧——诺:九九归一,以简驭繁

一、九九归一 国学道家中有物极必反的理念&#xff0c;所以&#xff0c;中国人有九九归一的说法&#xff0c;在基本数字中&#xff0c;九是大数&#xff0c;九九之意&#xff0c;相当于后天八卦一样&#xff0c;相当于一个系统完成了一次大的循环&#xff0c;九九归一&#xf…

数据资产赋能企业决策:通过精准的数据分析和洞察,构建高效的数据资产解决方案,为企业提供决策支持,助力企业实现精准营销、风险管理、产品创新等目标,提升企业竞争力

一、引言 在信息化和数字化飞速发展的今天&#xff0c;数据已成为企业最宝贵的资产之一。数据资产不仅包含了企业的基本信息&#xff0c;还蕴含了丰富的市场趋势、消费者行为和潜在商机。如何通过精准的数据分析和洞察&#xff0c;构建高效的数据资产解决方案&#xff0c;为企…

【Confluence】markdown格式转换为Confluence

简单的文本可以使用网站来快速转换&#xff0c;但是发现很多格式不能正确转换&#xff0c;所以研究了一个Py的方法来实现&#xff0c;如下&#xff1a; 安装Py插件 本方法主要借用markdown2 来实现&#xff0c;开始之前需要先安装一些库。 pip install markdown2 beautiful…

葡萄串目标检测YoloV8——从Pytorch模型训练到C++部署

文章目录 软硬件准备数据准备数据处理脚本模型训练模型部署数据分享软硬件准备 训练端 PytorchultralyticsNvidia 3080Ti部署端 fastdeployonnxruntime数据准备 用labelimg进行数据标注 数据处理脚本 xml2yolo import os import glob import xml.etree.ElementTree as ETxm…

如何在写代码中找到乐趣

平时我们写代码呢&#xff0c;多数情况都是流水线式写代码&#xff0c;基本就可以实现业务逻辑了。 如何在写代码中找到乐趣呢&#xff0c;我觉得&#xff0c;最好的方式就是&#xff1a;使用设计模式优化自己的业务代码。 参考资料&#xff1a; 实战&#xff01;工作中常用到…

【C++进阶9】异常

一、C语言传统的处理错误的方式 终止程序&#xff0c;如assert 如发生内存错误&#xff0c;除0错误时就会终止程序返回错误码 需要程序员自己去查找对应的错误 z如系统的很多库的接口函数都是通 过把错误码放到errno中&#xff0c;表示错误 二、C异常概念 异常&#xff1a;函…

企业出海的浪潮下,如何利用亚马逊云(AWS)更好地应对?

在全球化的浪潮下&#xff0c;越来越多的企业开始将目光投向国际市场。在这个数字化时代&#xff0c;云计算技术成为企业出海的必备利器之一。AWS云作为全球领先的云服务提供商&#xff0c;凭借其卓越的性能和完善的服务体系&#xff0c;成为众多企业出海的首选。 一、出海为什…

【Mybatis 与 Spring】事务相关汇总

之前分享的几篇文章可以一起看&#xff0c;形成一个体系 【Mybatis】一级缓存与二级缓存源码分析与自定义二级缓存 【Spring】Spring事务相关源码分析 【Mybatis】Mybatis数据源与事务源码分析 Spring与Mybaitis融合 SpringManagedTransaction&#xff1a; org.mybatis.spri…

小马搬运物品-第13届蓝桥杯省赛Python真题精选

[导读]&#xff1a;超平老师的Scratch蓝桥杯真题解读系列在推出之后&#xff0c;受到了广大老师和家长的好评&#xff0c;非常感谢各位的认可和厚爱。作为回馈&#xff0c;超平老师计划推出《Python蓝桥杯真题解析100讲》&#xff0c;这是解读系列的第89讲。 小马搬运物品&…

Redis 哨兵主备切换的数据丢失问题应该怎么解决?

引言&#xff1a;Redis作为一种高性能的内存数据库&#xff0c;广泛应用于分布式系统中。为了保证服务的高可用性&#xff0c;Redis提供了哨兵&#xff08;Sentinel&#xff09;机制&#xff0c;用于监控和管理Redis实例的自动故障恢复。然而&#xff0c;即使在哨兵的保护下&am…

计算机视觉中一些特殊的安装包

opencv-python Could not build wheels for opencv-python which use PEP 517 and cannot be installed 安装pip install opencv-python 输出 Collecting opencv-pythonDownloading https://files.pythonhosted.org/packages/77/f5/49f034f8d109efcf9b7e98fbc051878b83b2f02a1…

Windows宝塔面板部署ThinkPHP8.0创建Vue项目案例

安装ThinkPHP8.0 登录宝塔面板&#xff0c;创建一个站点。 输入composer代码&#xff0c;执行完成后自动创建TP目录 composer create-project topthink/think tp 网站目录设置为tp&#xff0c;运行目录设置为public 设置PHP版本为8.0以上&#xff0c;不然会出现下面的报错代…

【MotionCap】ImportError: cannot import name ‘packaging‘ from ‘pkg_resources‘

ImportError: cannot import name ‘packaging’ from ‘pkg_resources’ 降低setuptools的版本 参考大神:(ai-mocap) zhangbin@ubuntu-server:~/proj/04_mocap/third-party$ pip install -e neural_renderer

VBA 批量变换文件名

1. 页面布局 在“main”Sheet中按照下面的格式编辑。 2. 实现代码 Private wsMain As Worksheet Private intIdx As LongPrivate Sub getExcelBookList(strPath As String)Dim fso As ObjectDim objFile As ObjectDim objFolder As ObjectSet fso = CreateObject("Scrip…

为什么说BIM在机电安装行业是刚需?3D开发工具HOOPS如何促进BIM发展?

在建筑行业中&#xff0c;机电安装是一个复杂且精细的工程领域&#xff0c;它涉及到电气、管道、通风和控制系统等多个方面。随着建筑项目规模的不断扩大和复杂性的增加&#xff0c;传统的二维设计方法已经难以满足现代建筑的需求。正是在这种背景下&#xff0c;BIM技术应运而生…

第7章 Redis的噩梦:阻塞

文章目录 前言1 发现阻塞2.内在原因2.1API或数据结构使用不合理2.1.1如何发现慢查询2.1.2.如何发现大对象 2.2 CPU饱和2.3 持久化阻塞2.3.1fork阻塞2.3.2.AOF刷盘阻塞2.3.3.HugePage写操作阻塞 3 外在原因3.1CPU竞争3.2 内存交换 前言 Redis是典型的单线程架构&#xff0c;所有…

基于横纵向的混合联邦学习原理分析

近期陆续接触到关于混合联邦学习的概念&#xff0c;但基于横纵向的混合联邦实际的应用案例却几乎没有看到&#xff0c;普遍是一些实验性的课题&#xff0c;因此这一领域知识没有被很好普及。本篇文章的目的&#xff0c;主要是分析讨论关于横纵向混合联邦学习的业务场景、应用架…