Redis是一个基于内存 的key-value结构数据库。Redis 是互联网技术领域使用最为广泛的存储中间件。
官网: Redis - The Real-time Data PlatformDevelopers love Redis. Unlock the full potential of the Redis database with Redis Enterprise and start building blazing fast apps.https://redis.io 中文网: Redis中文网https://www.redis.net.cn/
简介
Redis是一种开源的、基于内存的键值对存储系统,具有高性能、丰富的数据类型和持久化等特点。它主要用于缓存服务器,同时也可作为消息中间件和Session共享等。具体如下:
- 性能优势:Redis全称为Remote Dictionary Server,是一款开源的基于内存的键值对存储系统,其主要被用作高性能缓存服务器使用。由于其基于内存的方式,免去了磁盘I/O速度的影响,使得其读写性能极高,能够支持每秒数十万次的读写操作。这使得Redis成为处理高并发请求的理想选择,尤其是在需要快速响应的场景中,如缓存、会话管理、排行榜等。
- 数据类型:Redis独特的键值对模型支持丰富的数据结构类型,包括字符串、哈希、列表、集合和有序集合。这些数据类型为开发者提供了灵活的数据操作能力,使Redis可以适应各种不同的应用场景。例如,利用有序集合可以实现排行榜功能,而原子性的自增操作则可以用于计数器和限速器。
- 持久化机制:Redis支持两种持久化方式,即RDB(快照)和AOF(只追加文件)。RDB通过定期将内存中的数据快照保存到磁盘实现数据持久化,而AOF则是记录每次写操作命令,以日志形式保存。这种持久化机制在突然断电等异常情况下能保证数据不丢失,提高了数据安全性。
- 应用场景:Redis不仅可以作为缓存系统,还可用于会话存储、实时分析、地理空间数据索引等场景。例如,在分布式系统中,利用Redis存储session信息,可以避免频繁登陆操作,提高用户体验。同时,Redis的发布/订阅模式使其可以作为简单的消息队列使用。
- 主从复制: Redis支持主从复制,可以通过从节点备份数据或分担读请求,从而提高数据的可用性和系统的伸缩性。主从复制不仅增强了数据的安全性,还实现了数据的备份和故障转移。
Redis服务启停
Redis服务的启动与停止可以通过多种方式进行操作,具体方法取决于安装方式和操作系统环境。在Linux系统中,常用的启停命令包括使用初始化脚本、配置文件和命令行工具等。以下是对各种启停方法的详细分析:
初始化脚本启动 :如果通过apt-get
或yum
包管理器安装Redis,可以使用初始化脚本来管理服务。常见的命令如下:
- 启动:
/etc/init.d/redis-server start
- 停止:
/etc/init.d/redis-server stop
- 重启:
/etc/init.d/redis-server restart
配置文件启动 :进入Redis的安装目录,运行redis-server
命令并指定配置文件。例如:
./redis-server /etc/redis/6379.conf
- 若需要以后台模式运行,可以添加
--daemonize yes
选项。
命令行工具启动 :直接使用redis-server
启动Redis,例如:
./redis-server --port 6380
(无密码启动)./redis-server .../redis.conf
(已设置访问密码启动)
客户端命令关闭 :使用redis-cli
工具执行shutdown
命令来安全停止Redis。例如:
redis-cli -h 127.0.0.1 -p 6379 shutdown
- 如果设置了密码,需添加
-a password
选项。
强制进程关闭 :如果正常关闭命令无效,可以使用kill -9 PID
命令强制结束Redis进程。首先查询Redis的PID:
ps aux | grep redis
找到PID,然后执行kill -9 PID
。
Redis数据类型
Redis 支持多种数据类型,包括字符串(String)、列表(List)、集合(Set)、有序集合(Sorted Set)、哈希(Hash)、位图(Bitmaps)、超日志(HyperLogLogs)和地理空间(Geospatial)等。这些数据类型各自具有独特的特点和使用场景,具体如下:
- 字符串(String):字符串是Redis最基本的数据类型,可以存储字符串、整数或浮点数,甚至是二进制数据。常用操作包括SET(设置键值对)、GET(获取键值)、INCR(自增键值)、APPEND(追加值)等。这种类型常用于缓存对象、分布式锁和计数器等场景。例如,可以将整个JSON字符串或图片作为字符串存储在Redis中。
- 列表(List):列表是一个双向链表,可以快速地从列表的头部或尾部插入或删除元素。常用命令包括LPUSH(从左侧插入)、RPUSH(从右侧插入)、LPOP(从左侧移除并返回元素)、RPOP(从右侧移除并返回元素)和LRANGE(获取指定范围的元素)等。列表适用于实现队列和栈,广泛应用于消息队列和时间线存储等。
- 集合(Set):集合是一个无序且不重复的字符串集合。它通过哈希表实现,添加、删除和查找的时间复杂度均为O(1)。常用命令包括SADD(添加元素)、SREM(移除元素)、SMEMBERS(获取所有元素)和SISMEMBER(判断元素是否在集合中)。集合常用于去重、社交网络中的好友推荐以及共同关注某类标签的用户。
- 有序集合(Sorted Set):有序集合类似于集合,但每个元素都有一个分数(score),根据这个分数进行排序。常用命令包括ZADD(添加元素和分数)、ZREM(移除元素)、ZRANGE(按分数范围获取元素)和ZCARD(获取集合大小)。适用于排行榜和时间线排序。
- 哈希(Hash):哈希包含键值对的集合,适合存储对象。每个哈希可以存储2^32-1个键值对。常用命令包括HSET(设置键值对)、HGET(获取键值)、HMGET(批量获取多个键值)和HDEL(删除一个或多个键值对)。哈希特别适用于存储用户信息、配置信息和其他对象类型的数据。
- 位图(Bitmaps):位图是基于字符串类型的数据结构,通过字符串的每一位来表示一个布尔值。操作命令包括SETBIT(设置特定位的值)、GETBIT(获取特定位的值)和BITCOUNT(统计指定范围内位值为1的个数)。位图非常适合用于需要大量标记的场景,如用户在线状态、活跃用户统计等。
- 超日志(HyperLogLog):超日志用于基数统计,即估算一个集合中的唯一元素数量。常用命令包括PFADD(添加元素到HyperLogLog)、PFCOUNT(统计唯一元素数量)等。这种数据类型适合于大数据集的基数统计,如网站UV统计。
- 地理空间(Geospatial):地理空间类型专门用于存储地理位置信息。常用命令包括GEOADD(添加地理位置)、GEODIST(计算两个位置之间的距离)、GEORADIUS(获取指定范围内的地理位置)。地理空间适用于物流跟踪、附近的人/物查询等场景。
Redis常用命令
字符串操作命令
SET:设置指定 key 的值。如果 key 已存在,则覆盖原有值。
- 用法:
SET key value
- 示例:
SET name "Redis tutorial"
- 设置键name
的值为"Redis tutorial"
。
GET:获取并返回指定 key 的值。如果 key 不存在,返回 nil。
- 用法:
GET key
- 示例:
GET name
- 获取键name
的值,返回"Redis tutorial"
。
MGET:一次性获取多个 key 的值。
- 用法:
MGET key1 key2 ...
- 示例:
MGET name description category
- 获取name
、description
和category
三个键的值。
APPEND:将给定的 value 追加到该 key 原来值的末尾。
- 用法:
APPEND key value
- 示例:
APPEND name " world"
- 在name
的值后面追加" world"
,变为"Redis tutorial world"
。
INCR:将 key 中储存的数字值增一。
- 用法:
INCR key
- 示例:
INCR pageviews
- 假设pageviews
当前为 5,执行后变为 6。
DECR:将 key 中储存的数字值减一。
- 用法:
DECR key
- 示例:
DECR inventory
- 假设inventory
当前为 10,执行后变为 9。
INCRBY:将 key 所储存的值加上指定的增量值。
- 用法:
INCRBY key increment
- 示例:
INCRBY score 5
- 假设score
当前为 10,执行后变为 15。
DECRBY:将 key 所储存的值减去指定的减量值。
- 用法:
DECRBY key decrement
- 示例:
DECRBY balance 20
- 假设balance
当前为 100,执行后变为 80。
GETRANGE:获取并返回指定 key 的字符串值中由 start 和 end 索引限定的子字符串部分。
- 用法:
GETRANGE key start end
- 示例:
GETRANGE content 0 9
- 获取content
的值从索引 0 到索引 9 的子字符串。
SETRANGE:用 value 参数覆写给定 key 所储存的字符串值,从偏移量 offset 开始。
- 用法:
SETRANGE key offset value
- 示例:
SETRANGE title 5 "Example"
- 假设title
当前为 "Hello World",执行后变为 "Hello Example"。
哈希操作命令
HSET:设置哈希表中指定字段的值。
- 用法:
HSET key field value
- 示例代码:
HSET user:1 "name" "Tom"
- 设置user:1
中的"name"
字段值为"Tom"
。 - 示例:
HSET user:1 "age" 25
- 设置user:1
中的"age"
字段值为25
。
HGET:获取哈希表中指定字段的值。
- 用法:
HGET key field
- 示例代码:
HGET user:1 "name"
- 获取user:1
中的"name"
字段值。 - 示例:
HGET user:1 "age"
- 获取user:1
中的"age"
字段值。
HMSET:同时设置哈希表中多个字段的值。
- 用法:
HMSET key field1 value1 field2 value2 ...
- 示例代码:
HMSET user:1 "name" "Tom" "age" 25 "occupation" "engineer"
- 设置user:1
中的多个字段。 - 示例:
HMSET user:2 "name" "Jerry" "age" 22 "occupation" "student"
- 设置user:2
中的多个字段。
HMGET:获取哈希表中多个字段的值。
- 用法:
HMGET key field1 field2 ...
- 示例代码:
HMGET user:1 "name" "age"
- 获取user:1
中的"name"
和"age"
字段值。 - 示例:
HMGET user:2 "name" "occupation"
- 获取user:2
中的"name"
和"occupation"
字段值。
HGETALL:获取哈希表中所有字段及其值。
- 用法:
HGETALL key
- 示例代码:
HGETALL user:1
- 获取user:1
中的所有字段和值。 - 示例:
HGETALL user:2
- 获取user:2
中的所有字段和值。
HDEL:删除哈希表中的指定字段。
- 用法:
HDEL key field1 field2 ...
- 示例代码:
HDEL user:1 "age"
- 删除user:1
中的"age"
字段。 - 示例:
HDEL user:2 "occupation"
- 删除user:2
中的"occupation"
字段。
HLEN:获取哈希表中字段的数量。
- 用法:
HLEN key
- 示例代码:
HLEN user:1
- 获取user:1
中的字段数量。 - 示例:
HLEN user:2
- 获取user:2
中的字段数量。
HEXISTS:检查哈希表中是否存在指定的字段。
- 用法:
HEXISTS key field
- 示例代码:
HEXISTS user:1 "name"
- 检查user:1
中是否存在"name"
字段。 - 示例:
HEXISTS user:2 "email"
- 检查user:2
中是否存在"email"
字段。
HKEYS:获取哈希表中所有的字段。
- 用法:
HKEYS key
- 示例代码:
HKEYS user:1
- 获取user:1
中的所有字段。 - 示例:
HKEYS user:2
- 获取user:2
中的所有字段。
HVALS:获取哈希表中所有字段的值。
- 用法:
HVALS key
- 示例代码:
HVALS user:1
- 获取user:1
中所有字段的值。 - 示例:
HVALS user:2
- 获取user:2
中所有字段的值。
列表操作命令
LPUSH:在列表头部插入一个或多个元素。
- 用法:
LPUSH key value1 value2 ...
- 示例代码:
LPUSH mylist "apple" "banana" "cherry"
- 将三个元素依次插入到名为mylist
的列表头部。
RPUSH:在列表尾部插入一个或多个元素。
- 用法:
RPUSH key value1 value2 ...
- 示例代码:
RPUSH mylist "apple" "banana" "cherry"
- 将三个元素依次插入到名为mylist
的列表尾部。
LPOP:移除并返回列表的第一个元素。
- 用法:
LPOP key
- 示例代码:
LPOP mylist
- 移除并返回名为mylist
的列表的第一个元素。
RPOP:移除并返回列表的最后一个元素。
- 用法:
RPOP key
- 示例代码:
RPOP mylist
- 移除并返回名为mylist
的列表的最后一个元素。
LLEN:获取列表的长度。
- 用法:
LLEN key
- 示例代码:
LLEN mylist
- 获取名为mylist
的列表的长度。
LINDEX:根据索引获取列表中的元素。
- 用法:
LINDEX key index
- 示例代码:
LINDEX mylist 0
- 获取名为mylist
的列表中第一个元素的值。
LRANGE:获取列表指定范围内的元素。
- 用法:
LRANGE key start stop
- 示例代码:
LRANGE mylist 0 2
- 获取名为mylist
的列表中前三个元素的值。
LREM:移除列表中指定数量的某个元素。
- 用法:
LREM key count value
- 示例代码:
LREM mylist 2 "apple"
- 从名为mylist
的列表中移除两个值为"apple"
的元素。
LSET:设置列表中指定索引位置的元素值。
- 用法:
LSET key index value
- 示例代码:
LSET mylist 1 "orange"
- 将名为mylist
的列表中第二个元素的值设置为"orange"
。
LINSERT:在列表中的某个元素之前或之后插入一个新元素。
- 用法:
LINSERT key BEFORE|AFTER pivot value
- 示例代码:
LINSERT mylist BEFORE "banana" "kiwi"
- 在名为mylist
的列表中,在值为"banana"
的元素之前插入一个新的元素"kiwi"
。
集合操作命令
SADD:向集合中添加一个或多个元素。
- 用法:
SADD key member1 member2 ...
- 示例代码:
SADD myset "apple" "banana" "cherry"
- 将三个元素添加到名为myset
的集合中。
SREM:从集合中移除一个或多个元素。
- 用法:
SREM key member1 member2 ...
- 示例代码:
SREM myset "banana" "cherry"
- 从名为myset
的集合中移除两个元素。
SISMEMBER:检查元素是否存在于集合中。
- 用法:
SISMEMBER key member
- 示例代码:
SISMEMBER myset "apple"
- 检查名为myset
的集合中是否包含元素"apple"
。
SMEMBERS:获取集合中的所有成员。
- 用法:
SMEMBERS key
- 示例代码:
SMEMBERS myset
- 获取名为myset
的集合中的所有成员。
SCARD:获取集合的成员数量。
- 用法:
SCARD key
- 示例代码:
SCARD myset
- 获取名为myset
的集合的成员数量。
SDIFF:返回第一个集合与其他集合的差集。
- 用法:
SDIFF key1 key2 ...
- 示例代码:
SDIFF myset1 myset2
- 返回名为myset1
的集合与名为myset2
的集合的差集。
SINTER:返回多个集合的交集。
- 用法:
SINTER key1 key2 ...
- 示例代码:
SINTER myset1 myset2
- 返回名为myset1
和myset2
的集合的交集。
SUNION:返回多个集合的并集。
- 用法:
SUNION key1 key2 ...
- 示例代码:
SUNION myset1 myset2
- 返回名为myset1
和myset2
的集合的并集。
SRANDMEMBER:随机返回集合中的一个或多个成员。
- 用法:
SRANDMEMBER key [count]
- 示例代码:
SRANDMEMBER myset 2
- 从名为myset
的集合中随机返回两个成员。
有序集合操作命令
ZADD:向有序集合中添加一个或多个成员,每个成员都有一个分数。
- 用法:
ZADD key score1 member1 [score2 member2 ...]
- 示例代码:
ZADD myzset 1 "apple" 2 "banana" 3 "cherry"
- 将三个元素添加到名为myzset
的有序集合中,并分别设置它们的分数为 1、2 和 3。
ZREM:从有序集合中移除一个或多个成员。
- 用法:
ZREM key member1 [member2 ...]
- 示例代码:
ZREM myzset "banana" "cherry"
- 从名为myzset
的有序集合中移除两个元素。
ZSCORE:获取有序集合中指定成员的分数。
- 用法:
ZSCORE key member
- 示例代码:
ZSCORE myzset "apple"
- 获取名为myzset
的有序集合中元素"apple"
的分数。
ZRANK:返回有序集合中指定成员的排名(按分数从小到大排序)。
- 用法:
ZRANK key member
- 示例代码:
ZRANK myzset "apple"
- 获取名为myzset
的有序集合中元素"apple"
的排名。
ZREVRANK:返回有序集合中指定成员的逆序排名(按分数从大到小排序)。
- 用法:
ZREVRANK key member
- 示例代码:
ZREVRANK myzset "apple"
- 获取名为myzset
的有序集合中元素"apple"
的逆序排名。
ZRANGE:返回有序集合中指定排名范围内的成员。
- 用法:
ZRANGE key start stop [WITHSCORES]
- 示例代码:
ZRANGE myzset 0 2 WITHSCORES
- 获取名为myzset
的有序集合中排名在 0 到 2 之间的成员及其分数。
ZREVRANGE:返回有序集合中指定逆序排名范围内的成员。
- 用法:
ZREVRANGE key start stop [WITHSCORES]
- 示例代码:
ZREVRANGE myzset 0 2 WITHSCORES
- 获取名为myzset
的有序集合中逆序排名在 0 到 2 之间的成员及其分数。
ZCARD:获取有序集合的成员数量。
- 用法:
ZCARD key
- 示例代码:
ZCARD myzset
- 获取名为myzset
的有序集合的成员数量。
ZCOUNT:返回有序集合中分数在指定区间内的成员数量。
- 用法:
ZCOUNT key min max
- 示例代码:
ZCOUNT myzset 1 3
- 获取名为myzset
的有序集合中分数在 1 到 3 之间的成员数量。
通用命令
GET:根据键获取值。
- 用法:
GET key
- 示例代码:
GET mykey
- 获取名为mykey
的键对应的值。
SET:设置键值对。
- 用法:
SET key value
- 示例代码:
SET mykey "Hello, Redis!"
- 设置名为mykey
的键的值为"Hello, Redis!"
。
KEYS:获取所有符合模式的键。
- 用法:
KEYS pattern
- 示例代码:
KEYS *mykey*
- 获取所有包含mykey
的键。
EXISTS:检查键是否存在。
- 用法:
EXISTS key [key ...]
- 示例代码:
EXISTS mykey
- 检查名为mykey
的键是否存在。
DEL:删除一个或多个键。
- 用法:
DEL key [key ...]
- 示例代码:
DEL mykey
- 删除名为mykey
的键。
EXPIRE:为键设置过期时间。
- 用法:
EXPIRE key seconds
- 示例代码:
EXPIRE mykey 3600
- 设置名为mykey
的键在 3600 秒后过期。
TTL:获取键的剩余过期时间。
- 用法:
TTL key
- 示例代码:
TTL mykey
- 获取名为mykey
的键的剩余过期时间。
TYPE:获取键的数据类型。
- 用法:
TYPE key
- 示例代码:
TYPE mykey
- 获取名为mykey
的键对应的数据类型。
PING:用于测试与Redis的连接是否畅通。
- 用法:
PING
- 示例代码:
PING
- 如果连接正常,返回结果为:PONG
。
Spring Data Redis
Spring Data Redis 是 Spring 的一部分,提供了在 Spring 应用中通过简单的配置就可以访问 Redis 服务,对 Redis 底层开发包进行了高度封装。在 Spring 项目中,可以使用Spring Data Redis来简化 Redis 操作。
集成
-
添加依赖 :在项目的
pom.xml
文件中添加spring-boot-starter-data-redis
依赖,这是整合 Redis 到 Spring Boot 项目的第一步。如果选择 Lettuce 作为 Redis 客户端,还需添加lettuce-core
依赖;若选择 Jedis,则需添加jedis
依赖。 -
配置连接 :修改
application.properties
或application.yml
配置文件,填入 Redis 服务器的连接信息,包括主机名、端口号以及其他相关配置。例如:javaspring.redis.host=localhost spring.redis.port=6379 spring.redis.password= # 如果设置了密码,则填写密码 spring.redis.database=0 # Redis数据库索引(默认为0)
-
选择客户端:Spring Data Redis 支持 Lettuce 和 Jedis 作为 Redis 客户端。Lettuce 基于 Netty 构建,支持非阻塞式 I/O,是 Spring Boot 2.x 中的默认客户端。Jedis 是一个老牌的 Redis 客户端,依然在一些场景中得到广泛应用。开发者可以根据需求选择合适的客户端。
操作数据
-
使用 RedisTemplate :
RedisTemplate
是 Spring Data Redis 提供的核心类,它提供了一组方法来执行 Redis 命令。例如,可以使用opsForValue()
方法来操作 Redis 字符串(String),用opsForList()
方法操作列表(List),以此类推。示例代码如下:java@Autowired private StringRedisTemplate stringRedisTemplate; public void setAndGetString() { stringRedisTemplate.opsForValue().set("key", "value"); String value = stringRedisTemplate.opsForValue().get("key"); System.out.println("Retrieved value: " + value); }
-
处理复杂数据结构 :对于哈希(Hash)等复杂数据结构,
RedisTemplate
提供了相应的操作方法。例如,使用opsForHash()
方法可以设置和获取哈希字段的值。此外,Spring Data Redis 还支持高级特性如事务、管道化命令和 Lua 脚本。
高级功能
- 消息发布和订阅 :Redis 的消息发布/订阅功能允许实现消息传递系统。Spring Data Redis 通过
RedisPubSubTemplate
提供了对这一功能的直接支持。发布者使用convertAndSend()
方法发布消息,而订阅者注册一个消息监听器来接收并处理这些消息。 - 缓存抽象 :Spring Data Redis 提供了一套缓存抽象,使开发者能够轻松实现缓存逻辑。通过使用
@Cacheable
注解,可以标记那些需要被缓存的方法,从而在调用这些方法时自动返回缓存的结果而非执行实际计算。 - 自定义序列化:为了更高效地处理 Java 对象与 Redis 数据类型之间的转换,Spring Data Redis 允许开发者自定义序列化策略。通过实现适当的序列化接口或类,可以控制对象的序列化和反序列化过程。
集群支持
- 连接集群 :Spring Data Redis 支持连接到 Redis 集群。通过配置
RedisClusterConfiguration
,可以创建一个连接到整个集群的RedisClusterConnection
对象。之后,使用RedisClusterCommands
可以执行集群特有的命令,例如clusterGetAll
。 - 哨兵模式 :在 Redis 集群环境中,Spring Data Redis 支持哨兵(Sentinel)模式以实现高可用性。通过配置
RedisSentinelConfiguration
,可以创建一个连接到主节点的连接工厂,并在主节点不可用时自动切换到从节点。
响应式编程支持
- ReactiveRedisTemplate :在响应式编程模型中,Spring Data Redis 提供了
ReactiveRedisTemplate
,它利用非阻塞式 I/O 操作 Redis 数据库。这使得在处理大量并发操作时能保持较低的延迟和高吞吐量。 - 流式 API :通过使用响应式 API,开发者可以利用
Flux
和Mono
类型来执行流式查询和异步操作,这大大简化了对响应式编程模型的使用。