Java笔记-----(7)缓存技术 Redis

Java笔记-----(7)缓存技术 Redis

缓存的使用可以减少网络请求或者查询数据库的次数,有效提高访问速度。

(1)redis 概述

redis(Remote Dictionary Server远程字典服务),是一款高性能的(key/value)分布式内存数据库,基于内存运行并支持持久化的NoSQL数据库。因为数据都在内存中,所以运行速度快。redis支持丰富的数据类型并且支持事务,事务中的所有命令会被序列化、按顺序执行,在执行的过程中不会被其他客户端发送来的命令打断。

NoSQL(NoSQL = Not Only SQL),意即“不仅仅是SQL”,是一项全新的数据库理念,泛指非关系型的数据库。

NoSQL数据库的产生就是为了解决大规模数据集合、多重数据种类带来的挑战,尤其是大数据应用难题。

(1.1)redis 相比 memcached 有哪些优势?(掌握)

Redis 与 Memcached 两者都是非关系型内存键值数据库,主要有以下不同:

数据类型
Memcached 仅支持字符串类型,而 Redis 支持五种不同的数据类型,可以更灵活地解决问题。
value大小不同,redis最大可以达到512MB,而memcache只有1MB

数据持久化
Redis 支持两种持久化策略:RDB 快照和 AOF 日志,而 Memcached 不支持持久化。

分布式
Memcached 不支持分布式,只能通过在客户端使用一致性哈希来实现分布式存储,这种方式在存储和查询时都需要
先在客户端计算一次数据所在的节点。而Redis Cluster 实现了分布式的支持。

内存管理机制

  • Redis 支持数据的备份,即master-slave模式的数据备份。在 Redis 中,并不是所有数据都一直存储在内存中,可以将一些很久没用的 value 交换到磁盘,而 Memcached 的数据则会一直在内存中。
  • Memcached 将内存分割成特定长度的块来存储数据,以完全解决内存碎片的问题。但是这种方式会使得内存的利用率不高,例如块的大小为 128 bytes,只存储 100 bytes 的数据,那么剩下的 28 bytes 就浪费掉了。
  • 使用底层模型不同,它们之间底层实现方式 以及与客户端之间通信的应用协议不一样。redis自己构建了VM 管理机制

(1.2)redis 支持的数据类型(掌握)

redis支持五种数据类型作为其Value,redis的Key都是字符串类型的。

键的类型只能为字符串,值支持五种数据类型:字符串、列表、集合、散列表、有序集合

注意:使用redis缓存一些不经常发生变化的数据,数据库的数据一旦发生改变,则需要更新缓存。

  • 数据库的表执行 增删改 的相关操作,需要将redis缓存数据情况,再次存入
  • 在service对应的增删改方法中,将redis数据删除。

在这里插入图片描述

① 字符串类型 string

redis 中字符串 value 最大可为512M。可以用来做一些计数功能的缓存(也是实际工作中最常见的)。

	1. 存储: set key value
		127.0.0.1:6379> set username zhangsan
		OK
	2. 获取: get key
		127.0.0.1:6379> get username
		"zhangsan"
	3. 删除: del key
		127.0.0.1:6379> del age
		(integer) 1

② 列表类型 list :linkedlist格式。支持重复元素

简单的字符串列表,按照插入顺序排序,可以添加一个元素到列表的头部(左边)或者尾部(右边),其底层实现是一个链表。可以实现一个简单消息队列功能,做基于redis的分页功能等支持重复元素

	1. 添加:
		1. lpush key value: 将元素加入列表左表
		2. rpush key value:将元素加入列表右边
			127.0.0.1:6379> lpush myList a
			(integer) 1
			127.0.0.1:6379> lpush myList b
			(integer) 2
			127.0.0.1:6379> rpush myList c
			(integer) 3
	2. 获取:
		* lrange key start end :范围获取
			127.0.0.1:6379> lrange myList 0 -1
			1) "b"
			2) "a"
			3) "c"
	3. 删除:
		* lpop key: 删除列表最左边的元素,并将元素返回
		* rpop key: 删除列表最右边的元素,并将元素返回

③ 集合类型 set :不允许重复元素

是一个字符串类型的无序集合。可以用来进行全局去重等。不允许重复元素

1. 存储:sadd key value
	127.0.0.1:6379> sadd myset a
	(integer) 1
	127.0.0.1:6379> sadd myset a
	(integer) 0 //不允许重复元素
2. 获取:smembers key:获取set集合中所有元素
	127.0.0.1:6379> smembers myset
	1) "a"
3. 删除:srem key value:删除set集合中的某个元素	
	127.0.0.1:6379> srem myset a
	(integer) 1

④ 有序集合类型 sorted set :不允许重复元素,且元素有顺序

是一个字符串类型的有序集合,给每一个元素一个固定的分数score来保持顺序。可以用来做排行榜应用或者进行范围查找等。不允许重复元素

不允许重复元素,且元素有顺序。每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。

	1. 存储:zadd key score value
		127.0.0.1:6379> zadd mysort 60 zhangsan
		(integer) 1
		127.0.0.1:6379> zadd mysort 50 lisi
		(integer) 1
		127.0.0.1:6379> zadd mysort 80 wangwu
		(integer) 1
	2. 获取:zrange key start end [withscores]
		127.0.0.1:6379> zrange mysort 0 -1
		1) "lisi"
		2) "zhangsan"
		3) "wangwu"

		127.0.0.1:6379> zrange mysort 0 -1 withscores
		1) "zhangsan"
		2) "60"
		3) "wangwu"
		4) "80"
		5) "lisi"
		6) "500"
	3. 删除:zrem key value
		127.0.0.1:6379> zrem mysort lisi
		(integer) 1

⑤ 哈希类型 hash :map 格式

键值对集合,是一个字符串类型的 Key和 Value 的映射表,也就是说其存储的Value是一个键值对(Key-Value)。可以用来存放一些具有特定结构的信息

	1. 存储: hset key field value
		127.0.0.1:6379> hset myhash username lisi
		(integer) 1
		127.0.0.1:6379> hset myhash password 123
		(integer) 1
	2. 获取: 
		* hget key field: 获取指定的field对应的值
			127.0.0.1:6379> hget myhash username
			"lisi"
		* hgetall key:获取所有的field和value
			127.0.0.1:6379> hgetall myhash
			1) "username"
			2) "lisi"
			3) "password"
			4) "123"
	3. 删除: hdel key field
		127.0.0.1:6379> hdel myhash username
		(integer) 1

其实redis还支持三种特殊的数据类型,分别为BitMap、Geo和HyperLogLog,自行了解

一般情况下,可以认为redis的支持的数据类型有上述五种,其底层数据结构包括:简单动态字符串,链表,字典,跳表,整数集合以及压缩列表

(1.3)redis 使用场景

计数器
可以对 String 进行自增自减运算,从而实现计数器功能。
Redis 这种内存型数据库的读写性能非常高,很适合存储频繁读写的计数量。

缓存
将热点数据放到内存中,设置内存的最大使用量以及淘汰策略来保证缓存的命中率。

查找表
例如 DNS 记录就很适合使用 Redis 进行存储。
查找表和缓存类似,也是利用了 Redis 快速的查找特性。但是查找表的内容不能失效,而缓存的内容可以失效,因为
缓存不作为可靠的数据来源。

消息队列
List 是一个双向链表,可以通过 lpush 和 rpop 写入和读取消息
不过最好使用 Kafka、RabbitMQ 等消息中间件。

会话缓存
可以使用 Redis 来统一存储多台应用服务器的会话信息。
当应用服务器不再存储用户的会话信息,也就不再具有状态,一个用户可以请求任意一个应用服务器,从而更容易实
现高可用性以及可伸缩性。

分布式锁实现
在分布式场景下,无法使用单机环境下的锁来对多个节点上的进程进行同步。
可以使用 Redis 自带的 SETNX 命令实现分布式锁,除此之外,还可以使用官方提供的 RedLock 分布式锁实现。

其它
Set 可以实现交集、并集等操作,从而实现共同好友等功能。
ZSet 可以实现有序性操作,从而实现排行榜等功能。

(1.4)redis 通用命令

	7. 通用命令
		1. keys * : 查询所有的键
		2. type key : 获取键对应的value的类型
		3. del key : 删除指定的key value

(1.5)redis 的配置文件

redis下载解压后:

  • redis.windows.conf:配置文件
  • redis-cli.exe:redis的客户端
  • redis-server.exe:redis服务器端

在配置文件中对redis进行了分模块配置,常用的模块如下:

  • NETWORK:该模块可以配置一些redis服务器地址,端口以及超时时间等
  • GENERAL:该模块可以对日志文件的路径和日志级别等进行配置
  • SNAPSHOTTING:redis持久化配置信息等
  • REPLICATION:redis集群配置等信息
  • MEMORY MANAGEMENT:内存管理,包括数据过期删除策略信息的设置
  • APPEND ONLY MODE:日志持久化方式信息设置

(2)redis是单线程的吗?为什么执行速度这么快?(重点掌握)

redis是单线程的,redis的单线程是指(网络请求模块)使用了一个线程,所以不需考虑并发安全性。但是对于需要依赖多个操作的复合操作来说,还是需要锁的,而且有可能是分布式锁。


那么单线程的redis为什么执行速度如此之快?

  • 基于内存实现,完全内存计算
  • 单线程操作,避免了线程上下文切换操作
  • 多路I/O复用的线程模型,实现了一个线程监控多个IO流,及时响应请求
  • redis对外部的依赖比较少,属于轻量级内存数据库

解析:

redis的线程模型多路I/O复用机制是一个比较重要并且常见的考察点。目前支持I/O多路复用的系统调用select,pselect,poll,epoll等函数。

I/O多路复用就是通过一种机制一个进程可以监视多个描述符,一旦某个描述符读就绪或者写就绪,其能够通知应用程序进行相应的读写操作。

多路I/O复用机制与多进程和多线程技术相比系统开销小,系统不必创建进程/线程,也不必维护这些进程/线程,从而大大减小了系统的开销。


关于常见函数的特点如下所示:

多路分离函数select(时间复杂度O(n))

  • 会修改传入的参数数组,这个对于一个需要调用很多次的函数,是非常不友好的。
  • 有最大监听连接数1024个的限制
  • 如果任何一个sock(I/O stream)出现了数据,select没有返回具体是哪个返回了数据,需要采用轮询的方式去遍历获取。所以select具有O(n)的无差别轮询复杂度
  • 线程不安全(当你在一个线程中已经监听该socket,另一个线程想要将该socket关闭,则结果会不可预知)
  • “If a file descriptor being monitored by select() is closed in another thread, the result is unspecified”

poll函数(时间复杂度O(n))

  • 去掉了1024的限制(使用链表搞定),没有最大连接数的限制
  • 不再修改传入的参数数组
  • 依然是线程不安全

epoll函数(时间复杂度O(1))

  • epoll 不仅返回socket组里面数据,还可以确定具体哪个socket有数据
  • 线程安全

epoll可以理解为event poll,不同于忙轮询和无差别轮询,epoll会把哪个流发生了怎样的I/O事件通知我们。所以我们说epoll实际上是事件驱动(每个事件关联上fd)的,此时我们对这些流的操作都是有意义的。(复杂度降低到了O(1))

IO多路复用机制详解

select、poll、epoll之间的区别(搜狗面试)

(3)使用redis可能出现的问题(重点掌握)

这里主要介绍Redis可能出现的三个问题:

(3.1)缓存雪崩

举例:
缓存同一时间大面积的失效,这个时候又来的一波请求都到数据库上,导致数据库连接异常

解决办法:
可以给缓存设置不同的缓存时间更新数据使用互斥锁或者通过双缓存在避免缓存雪崩。

(3.2)缓存穿透

举例:
故意的去请求缓存中不存在的数据,导致请求都打到了数据库上,导致数据库异常

解决办法:
可以使用互斥锁或者无论是否取到结果都将结果存入缓存,还可以使用有效的机制来拦截不合法的key值等。

(3.3)数据库和缓存的双写一致性问题

高并发请求下很容易导致数据不一致的问题,如果你的业务需要保证数据的强一致性,那么建议不要使用缓存。在数据库中和缓存数据的删除或者写入过程中,如果有失败的情况,会导致数据的不一致。

解决办法:

  • 双删延时的解决办法。可以先删除缓存数据,然后再更新数据库数据,最后再隔固定的时间再次删除缓存
  • 更新数据库产生的binlog订阅(使用canal)。将有变化的key记录下来,并且尝试去不断的去删除缓存(如果上次删除缓存失败)

(4)redis的持久化(重点掌握)

在redis中的介绍中,我们知道了redis不光是一个基于内存的缓存,同时还支持数据的持久化。在redis的配置文件模块介绍中,我们可以设置redis的持久化方式。redis的持久化方式有两种,即RDB和AOF的方式。

Redis 是内存型数据库,为了保证数据在断电后不会丢失,需要将内存中的数据持久化到硬盘上。

(4.1)RDB(快照方式 snapshotting)(全量持久化)

RDB:默认方式,不需要进行配置,默认就使用这种机制。

在一定的间隔时间中,检测key的变化情况,然后持久化数据

将当前内存中的数据集快照写入磁盘,实现数据的持久化,恢复时可以将快照重新载入内存。

  • 将某个时间点的所有数据都存放到硬盘上。
  • 可以将快照复制到其它服务器从而创建具有相同数据的服务器副本
  • 如果系统发生故障,将会丢失最后一次创建快照之后的数据。
  • 如果数据量很大,保存快照的时间会很长。

触发方式:

  • 自动触发:在配置文件中,可以配置执行了多少次save就自动触发自动持久化。
  • 手动触发:通过bgsave命令,在后台异步进行生成快照的操作,同时还可以响应客户端的请求。通过redis进程fork操作创建子进程,生成的快照由子进程负责,客户端请求只会在fork阶段被阻塞。
1. 编辑redis.windwos.conf文件
	#   after 900 sec (15 min) if at least 1 key changed
	save 900 1
	#   after 300 sec (5 min) if at least 10 keys changed
	save 300 10
	#   after 60 sec if at least 10000 keys changed
	save 60 10000

2. 重新启动redis服务器,并指定配置文件名称
	D:\redis\windows-64\redis-2.8.9>redis-server.exe redis.windows.conf	

快照恢复
备份文件 (dump.rdb) 移动到 redis 安装目录并启动服务,redis会自动加载快照文件数据到内存。但是,redis 服务器在载入 RDB 文件期间,会一直处于阻塞状态,直到载入工作完成为止。

优缺点分析:

  • RDB持久化方式存在数据的丢失,因为其没有办法实现实时持久化。因为bgsave每次运行都要执行fork操作创建子进程,属于重量级操作,频繁执行成本过高,会影响系统性能。自动触发也存在丢失部分数据的情况。
  • 在恢复大数据集时候,RDB方式相对于AOF要快。

(4.2)AOF(append-only-file)(增量持久化)

AOF:日志记录的方式,可以记录每一条命令的操作,将写命令添加到 AOF 文件(Append Only File)的末尾。可以每一次命令操作后,持久化数据 (对性能影响比较大)。

在 redis配置文件的 APPEND ONLY MODE 中,可以设置AOF持久化。通过记录redis服务器所执行的写命令来记录数据库状态。恢复时可以将AOF文件载入内存,并且可以通过 redis-check-aof --fix 进行修复AOF文件。

使用 AOF 持久化需要设置同步选项,从而确保写命令同步到磁盘文件上的时机。这是因为对文件进行写入并不会马
上将内容同步到磁盘上,而是先存储到缓冲区,然后由操作系统决定什么时候同步到磁盘。有以下同步选项:

在这里插入图片描述

  • always 选项会严重减低服务器的性能;
  • everysec 选项比较合适,可以保证系统崩溃时只会丢失一秒左右的数据,并且 Redis 每秒执行一次同步对服务
    器性能几乎没有任何影响;
  • no 选项并不能给服务器性能带来多大的提升,而且也会增加系统崩溃时数据丢失的数量。
1. 编辑redis.windwos.conf文件
	appendonly no(关闭aof) --> appendonly yes (开启aof)
	# appendfsync always : 每一次操作都进行持久化
	# appendfsync everysec : 每隔一秒进行一次持久化
	# appendfsync no	 : 不进行持久化

随着服务器写请求的增多,AOF 文件会越来越大。Redis 提供了一种将 AOF 重写的特性,能够去除 AOF 文件中的冗
余写命令。

AOF 日志重写

  • AOF文件会随着服务器运行的时间越来越大,可以通过AOF重写控制AOF文件的大小
  • AOF重写会首先读取数据库中现有的键值对状态,然后根据类型使用一条命令来替代前面对键值对操作的多条命令
  • 使用命令 bgrewriteaof 来实现AOF重写

redis 是单线程工作,当AOF文件较大时重写时间会比较长,在重写 AOF 期间,redis将长时间无法处理客户端请求。为了解决这个问题,可以将 AOF 重写程序放到子进程中执行,好处如下:

  • 子进程进行 AOF 重写期间,服务器进程(父进程)可以继续处理其它客户端请求。
  • 子进程带有父进程的数据副本,使用子进程而不是线程,可以在避免使用锁的情况下,保证数据的安全性

子进程中AOF重写导致的问题:

  • 子进程在进行 AOF 重写期间,服务器进程依然可以处理其它客户端请求,这就会导致数据库状态已经发生了改变,使得当前数据库数据状态重写后的AOF 文件中的数据不一致
  • 也就是出现了AOF文件和数据库中数据不一致的问题。

数据状态不一致解决办法:(AOF重写缓存区)

  • redis 服务器设置了一个 AOF重写缓冲区。这个缓冲区在创建子进程后开始使用,当redis服务器执行一个客户端的写请求命令,之后将这个写命令也发送到 AOF 重写缓冲区
  • 当子进程完成 AOF 日志重写之后,给父进程发送信号,父进程接收此信号后,将 AOF 重写缓冲区的内容写到新的 AOF文件中,保持数据的一致性。

优缺点分析:

  • AOF文件可以做到秒级持久化,使用追加写的方式来写入,可读性强并且可以使用命令进行文件修复。
  • 相比于RDB文件,同样数据下AOF文件体积要大。在redis负载较高时,秒级更新AOF文件会影响性能

(4.3)持久化策略选择

  • RDB持久化,安全性较差,它是正常时期数据备份及 master-slave 数据同步的最佳手段,文件尺寸较小并且恢复速度较快。在恢复大数据集时候,RDB方式相对于AOF要快
  • AOF更安全,可将数据及时同步到文件中,但需要较多的磁盘IO,AOF文件尺寸较大,文件内容恢复相对较慢也更加完整。

(5)redis数据的过期回收策略与内存淘汰机制

(5.1)过期回收策略

redis中的数据过期回收策略使用了定期删除和惰性删除相结合的方式。

  • 定期删除:
    redis会每隔一定的时间去抽查一定量的数据判断其是否过期,过期则进行删除。
  • 惰性删除:
    在获取一个key的时候,redis会检查这个key是否已经过期,若过期,则会进行删除操作。

(5.2)内存淘汰机制

可以设置内存最大使用量,当内存使用量超出时,会施行数据淘汰策略。

在配置文件中,我们可以对内存淘汰机制进行配置。当内存使用达到最大值时,redis可以使用的清除策略如下:

  • volatile-lru:利用LRU算法移除设置过过期时间的key (LRU:最近使用 Least Recently Used )
    已设置过期时间的数据集中挑选最近最少使用的数据淘汰
  • allkeys-lru:利用LRU算法移除任何key
    所有数据集中挑选最近最少使用的数据淘汰
  • volatile-random:移除设置过过期时间的随机key
    已设置过期时间的数据集中任意选择数据淘汰
  • allkeys-random:移除随机key
    所有数据集中任意选择数据进行淘汰
  • volatile-ttl:移除即将过期的key(minor TTL)
    已设置过期时间的数据集中挑选将要过期的数据淘汰
  • noeviction :不移除任何key,只是返回一个写错误 ,默认选项
    禁止驱逐数据

LRU算法在Java笔记-----(2)Java容器有讲过,查看详情请跳转

作为内存数据库,出于对性能和内存消耗的考虑,Redis 的淘汰算法实际实现上并非针对所有 key,而是抽样一小部
并且从中选出被淘汰的 key。

使用 Redis 缓存数据时,为了提高缓存命中率,需要保证缓存数据都是热点数据。可以将内存最大使用量设置为热点
数据占用的内存量
,然后启用 allkeys-lru 淘汰策略,将最近最少使用的数据淘汰。

Redis 4.0 引入了 volatile-lfuallkeys-lfu 淘汰策略,LFU 策略通过统计访问频率,将访问频率最少的键值对淘汰。

(6)redis的主从复制机制

当项目比较大的时候,我们可以使用主从架构Master/Slave机制Master 以写为主Slave 以读为主Master 主节点更新后根据配置,自动同步到从机Slave 节点

主从复制的原理包括旧版同步命令传播,主从复制的代价就是系统复制较重的时候会导致主从延迟,并且根据CAP理论,无法同时保证服务可用性和数据一致性。

redis 主从复制


(6.1)分布式CAP定理

SpringCloud-Eureka,Dubbo-Zookeeper
在这里插入图片描述

在这里插入图片描述

CAP理论是指 当网络分区发生时,一致性C和可用性A不可能同时保证。

  • C:Consistent 数据一致性
  • A:Availability 服务可用性
  • P:Partition tolerance 分区容错性
  • 网络分区:分布式系统的节点往往都是分布在不同的机器上进行网络隔离开的,这意味着必然会有网络断开的风险,网络断开也就意味着发生了网络分区。
  • 最终一致性:Redis可以保证最终一致性从节点会努力追赶主节点,最终从节点的状态会和主节点的状态将保持一致

(7)redis对事务支持

一个事务包含了多个命令,服务器在执行事务期间,不会改去执行其它客户端的命令请求。

事务中的多个命令被一次性发送给服务器,而不是一条一条发送,这种方式被称为流水线,它可以减少客户端与服务器之间的网络通信次数从而提升性能。

Redis 最简单的事务实现方式是使用 MULTIEXEC 命令将事务操作包围起来。

redis对事务的支持主要可以概括如下:

  • 隔离性:redis是单进程的程序,保证在执行事务时,不会对事务进行中断事务可以运行直到执行完所有事务队列中的命令为止。所以redis的事务支持隔离性。
  • redis会将一个事务中的所有命令序列化,然后按顺序执行。redis不可能在一个事务的执行过程中插入执行另一个客户端发出的请求。可以保证Redis将这些命令作为一个单独的隔离操作执行。

redis操作事务的相关命令如下所示:

  • MULTI:标记一个事务块的开始。
  • EXEC:执行所有事务块内的命令。
  • DISCARD:取消事务,放弃执行事务块内的所有命令。
  • UNWATCH:取消 WATCH 命令对所有 key 的监视。
  • WATCH key [key …]:监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。

需要注意的是redis的事务不支持回滚操作,redis 以 MULTI 开始一个事务,然后将多个命令入队到事务中,最后由 EXEC 命令触发事务, 一并执行事务中的所有命令。

只有当被调用的redis命令有语法错误时,这条命令才会执行失败,或者对某个键执行不符合其数据类型的操作,但是应该在将命令入队列的时候就应该并且能够发现这些问题,所以redis的事务不支持进行回滚操作

(8)Jedis

一款java操作redis数据库的工具,Jedis可以操作各种redis中的数据结构:

(8.1)Jedis操作字符串类型 string

set
get
//1. 获取连接
//如果使用空参构造,默认值 "localhost", 6379端口
Jedis jedis = new Jedis();
//2. 操作
//存储
jedis.set("username","zhangsan");
//获取
String username = jedis.get("username");
System.out.println(username);

//可以使用setex()方法存储可以指定过期时间的 key value
//将activecode:hehe键值对存入redis,并且20秒后自动删除该键值对
jedis.setex("activecode",20,"hehe");

//3. 关闭连接
jedis.close();

(8.2)Jedis操作哈希类型 hash :map格式

hset
hget
hgetAll
//1. 获取连接
//如果使用空参构造,默认值 "localhost",6379端口
Jedis jedis = new Jedis();
//2. 操作
// 存储hash
jedis.hset("user","name","lisi");
jedis.hset("user","age","23");
jedis.hset("user","gender","female");

// 获取hash
String name = jedis.hget("user", "name");
System.out.println(name);

// 获取hash的所有map中的数据
Map<String, String> user = jedis.hgetAll("user");

// keyset
Set<String> keySet = user.keySet();
for (String key : keySet) {
	//获取value
	String value = user.get(key);
	System.out.println(key + ":" + value);
}

//3. 关闭连接
jedis.close();

(8.3)Jedis操作列表类型 list :linkedlist格式,支持重复元素

lpush / rpush
lpop / rpop
lrange start end : 范围获取

//1. 获取连接
//如果使用空参构造,默认值 "localhost",6379端口
Jedis jedis = new Jedis();
//2. 操作
// list 存储
jedis.lpush("mylist","a","b","c");//从左边存
jedis.rpush("mylist","a","b","c");//从右边存

// list 范围获取
List<String> mylist = jedis.lrange("mylist", 0, -1);
System.out.println(mylist);

// list 弹出
String element1 = jedis.lpop("mylist");//c
System.out.println(element1);

String element2 = jedis.rpop("mylist");//c
System.out.println(element2);

// list 范围获取
List<String> mylist2 = jedis.lrange("mylist", 0, -1);
System.out.println(mylist2);

//3. 关闭连接
jedis.close();

(8.4)Jedis操作集合类型 set : 不允许重复元素

sadd
smembers:获取所有元素

//1. 获取连接
//如果使用空参构造,默认值 "localhost",6379端口
Jedis jedis = new Jedis();
//2. 操作
// set 存储
jedis.sadd("myset","java","php","c++");
// set 获取
Set<String> myset = jedis.smembers("myset");
System.out.println(myset);

//3. 关闭连接
jedis.close();

(8.5)Jedis操作有序集合类型 sortedset:不允许重复元素,且元素有顺序

zadd
zrange

//1. 获取连接
//如果使用空参构造,默认值 "localhost",6379端口
Jedis jedis = new Jedis();
//2. 操作
// sortedset 存储
jedis.zadd("mysortedset",3,"亚瑟");
jedis.zadd("mysortedset",30,"后裔");
jedis.zadd("mysortedset",55,"孙悟空");

// sortedset 获取
Set<String> mysortedset = jedis.zrange("mysortedset", 0, -1);
System.out.println(mysortedset);

//3. 关闭连接
jedis.close();

(8.6)jedis连接池:JedisPool

//0.创建一个配置对象
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(50);
config.setMaxIdle(10);
//1.创建JedisPool连接池对象
JedisPool jedisPool = new JedisPool(config,"localhost",6379);
//2.调用方法 getResource()方法获取Jedis连接
Jedis jedis = jedisPool.getResource();
//3. 使用
jedis.set("hehe","heihei");
//4. 关闭 归还到连接池中
jedis.close();

连接池工具类:

public class JedisPoolUtils {

	private static JedisPool jedisPool;

	static{
		//读取配置文件
		InputStream is = 
			JedisPoolUtils.class.getClassLoader().getResourceAsStream("jedis.properties");
		//创建Properties对象
		Properties pro = new Properties();
		//关联文件
		try {
			pro.load(is);
		} catch (IOException e) {
			e.printStackTrace();
		}

		//获取数据,设置到JedisPoolConfig中
		JedisPoolConfig config = new JedisPoolConfig();
		config.setMaxTotal(Integer.parseInt(pro.getProperty("maxTotal")));
		config.setMaxIdle(Integer.parseInt(pro.getProperty("maxIdle")));

		//初始化JedisPool
		jedisPool = new JedisPool(config,
								pro.getProperty("host"),
								Integer.parseInt(pro.getProperty("port")));
	}


	/**
	* 获取连接方法
	*/
	public static Jedis getJedis(){
		return jedisPool.getResource();
	}
}

(9)Redis实现分布式锁,如何加锁以及解锁

关于分布式锁,为了使得加锁操作具有原子性,不可以使用多条命令来完成,我们可以使用带多个参数的set命令来完成,如下所示:jedis.set(String key, String value, String nxxx, String expx, int time)

  • 第一个为key,我们使用key来当锁,因为key是唯一的。
  • 第二个为value,我们传的是requestId,通过给value赋值为requestId,我们就知道这把锁是哪个请求加的了,在解锁的时候就可以有依据。
  • 第三个为nxxx,这个参数我们填的是NX,意思是SET IF NOT EXIST,即当key不存在时,我们进行set操作;若key已经存在,则不做任何操作;
  • 第四个为expx,这个参数我们传的是PX,意思是我们要给这个key加一个过期的设置,具体时间由第五个参数决定。
  • 第五个为time,与第四个参数相呼应,代表key的过期时间。

(10)Redis集群中的哨兵模式,主从复制等

待更新

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值