• Redis的基本使用


    1.Redis简介

    (1)什么是Redis
    ①Redis是一个基于内存的key-value结构数据库
    ②基于内存存储,读写性能高
    ③适合存储热点数据(热点商品、资讯、新闻)
    ④Redis是一个开源的内存中的数据结构存储系统,它可以用作:数据库、缓存和消息中间件
    ⑤它存储的value类型比较丰富,也被称为结构化的NoSql数据库。NoSql,不仅仅是SQL,泛指非关系型数据库。NoSql数据库
    并不是要取代关系型数据库,而是关系型数据库的补充。
    (2)Redis应用场景
    ①缓存
    ②任务队列
    ③消息队列
    ④分布式锁
    (3)Redis默认有16个数据库,类似数组下标从0开始,初始默认用0号库
    ①使用命令 select 来切换数据库。如select 8
    ②统一密码管理,所有库使用统一密码
    ③dbsize :查看当前数据库的key的数量
    ④flushdb:清空当前库
    ⑤通杀全部库
    (4)Redis是单线程+多路IO复用技术
    多路复用是指使用一个线程来检查多个文件描述符(Socket)的就绪状态,比如调用select和poll函数,传入多个文件描述符,如果有一个文件描述符就绪,则返回,否则阻塞直到超时。得到就绪状态后进行真正的操作可以在同一个线程里执行,也可以启动线程执行(比如使用线程池)
    与Memcache的三点不同:支持多数据类型,支持持久化,单线程+多路复用

    2.Redis常用操作命令

    2.1 键(key)

    ①keys * 查看当前库所有key
    ②exists key 判断某个key是否存在
    ③type key 查看你的key是什么类型
    ④del key 删除指定的key数据
    ⑤unlink key 根据value选择非阻塞删除(仅将key从keyspace元数据中删除,真正的删除会在后续异步操作)
    ⑥expire key 时间(时间单位:秒,为给定的key设置过期时间
    ⑦ttl key 查看还有多少秒过期,-1表示永不过期,-2表示已过期

    2.2 字符串(String)

    (1)String是Redis最基本的类型,可以理解成与Memcached一模一样的类型,一个key对应一个value
    (2)String类型是二进制安全的,意味着Redis的String可以包含任何数据。比如jpg图片或者序列化的对象
    (3)String类型是Redis最基本的数据类型,一个Redis中字符串value最多可以是512M
    (4)String的数据结构为简单动态字符串(Simple Dynamic String,缩写SDS).是可以修改的字符串,内部结构实现上类似于
    Java的ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配
    ①set key value //设置指定key的值
    补充:mset key1 value1 key2 value2 … // 同时设置一个或多个 key-value
    ②get key // 获取指定key的值
    补充:mget key1 value1 key2 value2 … // 同时获取一个或多个 key-value
    ③setex key 过期时间 value // 设置指定key的值,并将key的过期时间设为 seconds 秒
    ④setnx key value // 只有在key不存在时设置 key 的值
    补充:msetnx key1 value1 key2 value2 …
    //同时设置一个或多个key-value对,当且仅当所有给定key都不存在(原子性,有一个失败则都失败)
    ⑤strlen key 获得值的长度
    ⑥incr key 将key中存储的数字值增1,只能对数字值操作,如果为空,新增值为1
    ⑦decr key 将key中存储的数字值减1
    补充:incr key 对存储在指定key的数值执行原子的加1操作
    所谓原子操作是指不会被线程调度机制打断的操作,这种操作一旦开始,就一直运行到结束,中间不会
    有任何 context switch(切换到另一个线程)
    1.在单线程中,能够在单条指令中完成的操作都可以认为是“原子操作”,因为中断只能发生于指令之间
    2.在多线程中,不能被其他进程(线程)打断的操作就叫原子操作。
    Redis单命令的原子性主要得益于Redis的单线程
    ⑧getrange key 起始位置 结束位置
    获得值的范围,类似于java中的subString(这里是 前包,后包)
    ⑨setrange key 起始位置 value
    用value覆写key所存储的字符串值,从<起始位置>开始(索引从0开始)
    ⑩getset key value //以旧换新,设置了新值的同时获得旧值

    2.3 列表list操作命令

    Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部或者尾部。List的数据结构为快速链表quickList,首先在列表元素比较少的情况下会使用一块连续的内存存储,这个结构是ziplist,也就是压缩列表。它将所有的元素紧挨着一起存储,分配的是一块连续的内存。当数据量比较大时才会改成quicklist。因为普通的链表需要的附加指针空间太大,会比较浪费空间。Redis将链表和ziplist结合起来组成了quicklist。也就是将多个ziplist使用双向指针串起来使用。这样既满足了快速的插入删除性能,又不会出现太大的空间冗余。
    ①lpush/rpush key value1 value2 … // 将一个或多个值插入到列表头部/尾部
    例如:lpush mylist a b c
    ②lrange key start stop //按照索引下标获得元素(从左到右)
    例如:lrange mylist 0 -1 // 0 -1表示获取所有
    ③lpop/rpop key // 从左边/右边吐出一个值(值在键在,值光键亡)
    ④llen key // 获取列表长度
    ⑤brpop key1 key2 … timeout // 移出并获取列表的最后一个元素,或发现可弹出元素为止
    //timeout 超时时间;列表没有元素,就会一直阻塞直到超时
    ⑥lindex key index 按照索引下标获得元素(从左到右)

    2.4 集合set操作命令

    Redis的set 是string类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。它的底层其实是一个
    value为null的hash表,所以添加,删除,查找的复杂度都是O(1)
    ①sadd key member1 member2 … //向集合中添加一个或多个成员
    ②smembers key // 返回集合中的所有成员
    ③sismember key value // 判断集合key是否为含有该value值,有1,没有0
    ④scard key // 返回该集合的元素个数
    ⑤sinter key1 key2 … // 返回给定所有集合的交集
    ⑤sunion key1 key2 … // 返回所有给定集合的并集
    ⑥sdiff key1 key2 … // 返回给定所有集合的差集(key1中有的,不包含key2中的)
    ⑦srem key member1 member2 … // 移除集合中一个或多个成员
    smove value // 把集合中一个值从一个集合移动到另一个集合
    ⑨spop key // 随机从该集合中吐出一个值

    2.5 有序集合Zset(sorted set)操作命令

    Redis sorted set 有序集合是string类型元素的集合,且不允许重复的成员。每个元素都会关联一个double类型的分数(score)。
    redis正是通过分数来为集合中的成员进行从小到大排序。有序集合的成员是唯一的,但分数却可以重复。
    ①zadd key score1 member1 score2 member2 … // 向有序集合中添加一个或多个成员,或者更新已存在成员的分数
    ②zrange key start stop [WITHSCORS] // 通过索引区间返回有序集合中指定区间内的成员(withscors可以带分数一起返回)
    ③zincrby key increment member // 有序集合中对指定成员的分数加上增量 increment
    ④zrem key member [member …] // 移除有序集合中的一个或多个成员
    zset底层使用了两个数据结构:
    (1)hash,hash的作用就是关联元素value和权重score,保障元素value的唯一性,可以通过元素value找到对应的score值。
    (2)跳跃表,跳跃表的目的在于给元素value排序,根据score的范围获取元素列表

    2.6 哈希 hash 操作命令

    Redis hash是一个String类型的filed和value的映射表,hash特别适合用于存储对象。hash类型对应的数据结构是两种:
    ziplist(压缩列表),hashtable(哈希表)。当field-value长度较短且个数较少时,使用ziplist,否则使用hashtable
    ①hset key filed value // 将哈希表key中的字段field的值设为value
    ②hget key field // 获取哈希表中指定字段的值
    ③hdel key field // 删除存储在哈希表中的指定字段
    ④hkeys key // 获取哈希表中所有字段
    ⑤hvals key // 获取哈希表中所有值
    ⑥hgetall key // 获取在哈希表中指定key的所有字段和值
    在这里插入图片描述

    2.7 通用命令

    ①KEYS pattern // 查找所有符合给定模式(pattern的)key
    例如: keys *
    ②EXISTS key // 检查给定 key 是否存在
    ③TYPE key // 返回key所存储的值的类型
    例如:type myset
    ④TTL key // 返回给定 key 的剩余生存时间,以秒为单位
    例如:ttl name
    ⑤DEL key // 该命令用于在key存在时删除key

    3.Redis的新数据类型

    3.1 Bitmaps

    (1)简介
    现代计算机采用二进制(位)作为信息的基础单位,1个字节等于8位,例如“abc”字符串是由3个字节组成,但实际在计算机
    存储时将其用二进制表示,“abc”分别对应的ASCII码分别是97、98、99,对应的二进制分别是01100001、01100010和
    01100011。合理的使用操作位能够有效地提高内存使用率和开发效率。Redis提供了Bitmaps这个“数据类型”可以实现对
    位的操作
    ①Bitmaps本身不是一种数据类型,它实际上就是字符串(key-value),但是它可以对字符串的位进行操作
    ②Bitmaps单独提供了一套命令,所以在Redis中使用Bitmaps和使用字符串的方法不太相同。可以把Bitmaps想象成一个
    以位为单位的数组,数组的每个单位只能存储0和1,数组的下标在Bitmaps中叫做偏移量。
    (2)格式
    ①setbit key offset value // 设置Bitmaps中某个偏移量的值(0或1),偏移量offset从0开始
    ②getbit key offset // 获取Bitmaps中某个偏移量的值
    ③bitcount key start end // 统计字符串从start字节到end字节比特值为1的数量

    4.Redis的配置文件介绍

    4.1 ###Units单位###

    配置大小单位,开头定义了一些基本的度量单位,只支持 bytes,不支持 bit ,大小写不敏感

    4.2 ###INCLUDES包含###

    类似于jsp中的 include,多实例的情况可以把公用的配置文件提取出来

    4.3 ###网络相关配置

    (1)bind
    默认情况下 bind = 127.0.0.1 只能接受本机的访问请求,不写的情况下,无限制接受任何ip地址的访问
    (2)protected-mode
    如果开启了protected-mode,那么在没有设定bind ip且没有设密码的情况下,Redis只允许接受本机的响应
    (将本机访问保护模式设置no)
    (3)Port:端口号,默认 6379
    (4)tcp-backlog
    ①设置tcp的backlog,backlog其实是一个连接队列,backlog队列总和=未完成三次握手队列 + 已经完成
    三次握手队列。
    ②在高并发环境下你需要一个高backlog值来避免慢客户端连接问题。
    注意Linux内核会将这个值减小到/proc/sys/net/core/somaxconn的值(128),所以需要确认增大/proc/sys/net/core/somaxconn和/proc/sys/net/ipv4/tcp_max_syn_backlog(128)两个值来达到想要的效果
    (5)timeout
    一个空闲的客户端维持多少秒会关闭,0表示关闭该功能。即永不关闭。
    (6)tcp-keepalive
    ①对访问客户端的一种心跳检测,每隔n秒检测一次。
    ②单位为秒,如果设置为0,则不会进行Keepalive检测,建议设置成60
    ③如果还活着继续提供服务,不活着就释放连接

    4.4 ###GENERAL通用###

    (1)daemonize
    是否为后台进程,设置为yes。守护进程,后台启动
    (2)pidfile
    存放pid文件(存放进程号)的位置,每个实例会产生一个不同的pid文件
    (3)loglevel
    ①指定日志记录级别,Redis总共支持四个级别:debug、verbose、notice、warning,默认为notice
    ②四个级别根据使用阶段来选择,生产环境选择notice 或者warning
    (4)logfile:设置日志的输出文件路径,默认为空
    (5)databases
    设定库的数量 默认16,默认使用0号数据库,可以使用SELECT 命令在连接上指定数据库id

    4.5. ###SECURITY安全###

    (1)设置密码
    ①默认是没有密码的,设置密码可以把下面的注释打开
    在这里插入图片描述
    ②在命令行中设置密码,只是临时的。重启redis服务器,密码就还原了。
    在这里插入图片描述
    ③永久设置,需要在配置文件中进行配置

    4.6 #### LIMITS限制

    (1)maxclients
    ①设置redis同时可以与多少个客户端进行连接
    ②默认情况下为 10000 个客户端
    ③如果达到了此限制,redis则会拒绝新的连接请求,并且向这些连接请求方
    发出“max number of clients reached”以作回应。
    (2)maxmemory
    ①建议必须设置,否则,将内存占满,造成服务器宕机
    ②设置redis可以使用的内存量。一旦到达内存使用上限,redis将会试图移除内部数据,移除规则可以
    通过maxmemory-policy来指定。
    ③如果redis无法根据移除规则来移除内存中的数据,或者设置了“不允许移除”,那么redis则会针对那些
    需要申请内存的指令返回错误信息,比如SET、LPUSH等。
    ④但是对于无内存申请的指令,仍然会正常响应,比如GET等。如果你的redis是主redis(说明你的redis有从redis),
    那么在设置内存使用上限时,需要在系统中留出一些内存空间给同步队列缓存,只有在你设置的是“不移除”的
    情况下,才不用考虑这个因素。
    (3)maxmemory-policy
    ①volatile-lru:使用LRU算法移除key,只对设置了过期时间的键;(最近最少使用)
    ②allkeys-lru:在所有集合key中,使用LRU算法移除key
    ④volatile-random:在过期集合中移除随机的key,只对设置了过期时间的键
    ⑤allkeys-random:在所有集合key中,移除随机的key
    ⑥volatile-ttl:移除那些TTL值最小的key,即那些最近要过期的key
    ⑦noeviction:不进行移除。针对写操作,只是返回错误信息
    (4)maxmemory-samples
    ①设置样本数量,LRU算法和最小TTL算法都并非是精确的算法,而是估算值,所以你可以设置样本的大小,redis默认
    会检查这么多个key并选择其中LRU的那个。
    ②一般设置3到7的数字,数值越小样本越不准确,但性能消耗越小

    5.Redis的发布和订阅

    5.1 什么是发布和订阅

    (1)Redis发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息
    (2)Redis客户端可以订阅任意数量的频道
    在这里插入图片描述

    5.2 发布订阅命令行实现

    (1)打开一个客户端订阅 channel1
    subscribe channel1
    (2)打开另一个客户端,给channel1发布消息hello
    publish channel1 hello // 返回的1是订阅者数量
    (3)打开第一个客户端可以看到发送的消息
    注:发布的信息没有持久化,如果在订阅的客户端收不到hello,只能收到订阅后发布的信息

    6.在Java中操作Redis

    5.1 使用Jedis操作Redis

    (1)导入相关坐标

      <!--   Jedis坐标   -->
            <dependency>
                <groupId>redis.clients</groupId>
                <artifactId>jedis</artifactId>
                <version>2.8.1</version>
            </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    (2)相关实例

    public class JedisTest {
        @Test
        public void testJedis() {
    //        1.获取连接
            Jedis jedis = new Jedis("localhost", 6379);
    //        2.执行具体的操作
            jedis.set("username","lisi");
            String value = jedis.get("username");
            System.out.println(value);
    //        3.关闭连接
            jedis.close();
        } }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    6.2 在Spring Boot项目使用Spring Data Redis操作Redis

    Spring Data Redis 中提供了一个高度封装的类:RedisTemplate,针对jedis客户端中大量api进行了归类封装,将同一类型操作
    封装为opperation接口,具体分类如下:
    ①ValueOperations:简单K-V操作
    ②SetOperations:set类型数据操作
    ③ZSetOperations:zset类型数据操作
    ④HashOperations:针对map类型的数据操作
    ⑤ListOperations:针对list类型的数据操作
    (1)导入相关坐标

    <!--  Spring Data Redis -->
     <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
     </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    (2)Redis相关配置

    spring:
    # Redis相关配置
      redis:
        host: localhost
        port: 6379
        database: 0 # 默认有16个数据库,操作的是第0号数据库
        jedis:
    # Redis连接池配置
          pool:
            max-active: 8 # 最大连接数
            max-wait: 1ms # 连接池最大阻塞等待时间
            max-idle: 14 # 连接池中的最大空闲连接
            min-idle: 0 # 连接池中的最小空闲连接
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    (3)Redis配置

    @Configuration
    public class RedisConfig {
        @Bean
        public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
    //        创建RedisTemplate对象
            RedisTemplate<Object, Object> template = new RedisTemplate<>();
    //        设置连接工厂
            template.setConnectionFactory(connectionFactory);
    //        创建JSON序列化工具
            GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
    //        设置key的序列化
            template.setKeySerializer(RedisSerializer.string());
            template.setHashKeySerializer(RedisSerializer.string());
    //       设置value的序列化
            template.setValueSerializer(jsonRedisSerializer);
            template.setHashValueSerializer(jsonRedisSerializer);
    //        返回
            return template;
        }  }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    (3)实例

    @SuppressWarnings("all")
    @SpringBootTest(classes = SsmMangerApplication.class)
    @RunWith(SpringRunner.class)
    public class SpringDataRedisTest {
        @Autowired
        private RedisTemplate redisTemplate;
    
        //操作String类型数据
        @Test
        public void testString() {
            redisTemplate.opsForValue().set("city", "beijing");
            Object city = redisTemplate.opsForValue().get("city");
            System.out.println(city);
        }
        //    操作Hash类型数据
        @Test
        public void testHash() {
            HashOperations hashOperations = redisTemplate.opsForHash();
    //        存值
            hashOperations.put("002", "name", "xaioming");
            hashOperations.put("002", "age", "20");
            hashOperations.put("002", "address", "bj");
    //        取值
            String age = (String) hashOperations.get("002", "age");
            System.out.println(age);
    //        获得hash结构中的所有字段
            Set keys = hashOperations.keys("002");
            for (Object key : keys) {
                System.out.println(key);
    //            获得hash结构中的所有值
                List values = hashOperations.values("002");
                for (Object value : values) {
                    System.out.println(value);
                } } }
        //操作List类型的数据
        @Test
        public void testList() {
            ListOperations listOperations = redisTemplate.opsForList();
    //        存值
            listOperations.leftPush("mylist", "a");
            listOperations.leftPushAll("mylist", "b", "c", "d");
    //        取值
            List<String> mylist = listOperations.range("mylist", 0, -1);
            for (String value : mylist) {
                System.out.println(value);
            }
    //        出队列
            Object element = listOperations.rightPop("mylist");
            System.out.println(element);
        }
    
        //    操作set类型的数据
        @Test
        public void testSet() {
            SetOperations setOperations = redisTemplate.opsForSet();
    //        存值
            setOperations.add("myset", "a", "b", "c", "a");
    //        取值
            Set<String> myset = setOperations.members("myset");
            for (String o : myset) {
                System.out.println(o);
            }
    //      删除成员
            setOperations.remove("myset", "a", "b");
    //        取值
            myset = setOperations.members("myset");
            for (String o : myset) {
                System.out.println(o);
    
            }
        }
    
        //    操作ZSet类型的数据
        @Test
        public void testZSet() {
            ZSetOperations zSetOperations = redisTemplate.opsForZSet();
    //        存值
            zSetOperations.add("myZset", "a", 10.0);
            zSetOperations.add("myZset", "b", 11.0);
            zSetOperations.add("myZset", "c", 12.0);
            zSetOperations.add("myZset", "a", 13.0);
    
    //                取值
            Set<String> myZSet = zSetOperations.range("myZset", 0, -1);
            for (String s : myZSet) {
                System.out.print(s);//bca
            }
    
    //                修改分数
            zSetOperations.incrementScore("myZset", "b", 20.0);
    
    //                取值
    
            myZSet = zSetOperations.range("myZset", 0, -1);
            System.out.println();
            for (String s : myZSet) {
                System.out.print(s);//cab
            }
    //                删除成员
            zSetOperations.remove("myZset", "a", "b");
    //        取值
            myZSet = zSetOperations.range("myZset", 0, -1);
            System.out.println();
            for (String s : myZSet) {
                System.out.print(s);//c
            }
        }
    
    //    通用操作
        @Test
        public void testCommon(){
    //        获取Redis中所有的key
    
            Set<String> keys = redisTemplate.keys("*");
            for (String key : keys) {
                System.out.print(key);
            }
    //        判断某个key是否存在
            Boolean haha = redisTemplate.hasKey("haha");
            System.out.println(haha);
    
    //        删除指定key
            redisTemplate.delete("myZset");
    
    //        获取指定key对应的value的数据类型
            DataType dataType = redisTemplate.type("myset");
            System.out.println(dataType.name());
        } }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
  • 相关阅读:
    Netty 学习(六):创建 NioEventLoopGroup 的核心源码说明
    UDS入门至精通系列:Service 23
    SpringBoot启动代码和自动装配源码分析
    认识异常-java
    matlab学习笔记(六)
    7-39 计算阶乘和
    ReactRouter——路由配置、路由跳转、带参跳转、新route配置项
    spring cloud 使用oauth2 问题收集
    【算子2】spark(四):spark core:trans算子中key-value类型的算子使用说明
    2022最新最全Java 进阶资料合集
  • 原文地址:https://blog.csdn.net/y516369/article/details/126909905