1.什么是Redis?
Redis(Remote Dictionary Server)是一个开源的内存数据存储系统,通过使用键值对的方式进行数据存储。它支持多种数据结构,包括字符串(string)、哈希(hash)、列表(list)、集合(set)、有序集合(sorted set)等。
Redis 的主要特点包括:
- 内存存储:Redis 将所有数据存储在内存中,这使得它非常快速和高效。同时,Redis 也支持将数据持久化到磁盘,以保证数据的持久性。
- 高性能:Redis 是单线程的,通过使用异步的方式处理网络请求,使得 Redis 能够处理高并发的情况。
- 多数据结构支持:Redis 提供了多种丰富的数据结构,可以满足不同场景下的数据存储需求。
- 支持事务:Redis 提供了简单的事务支持,可以通过 MULTI、EXEC、DISCARD 和 WATCH 等命令实现事务操作。
- 发布/订阅:Redis 支持发布/订阅模式,可以实现消息的发布和订阅,用于构建实时的消息系统。
- 高可用性:Redis 提供了主从复制和哨兵机制,以实现数据的高可用性和故障转移。
2.怎么安装?
Linux系统
-
在 Redis 官方网站上下载最新的 Redis 软件包:http://redis.io/download 。
-
解压下载的 Redis 软件包。使用以下命令解压:
$ tar xvzf redis-x.x.x.tar.gz
其中 “x.x.x” 是 Redis 的版本号。
-
进入解压后的 Redis 目录:
$ cd redis-x.x.x
-
在 Redis 目录中,执行以下命令编译 Redis:
$ make
这将编译 Redis 的可执行文件。
-
安装 Redis。执行以下命令:
$ make install
这将把 Redis 的可执行文件和相关的配置文件放置到系统默认的目录中。
-
配置 Redis。在 Redis 目录中,复制
redis.conf
配置文件到指定位置:$ cp redis.conf /etc/redis.conf
可以根据需要修改
redis.conf
文件中的配置选项,比如设置密码、修改监听端口等。 -
启动 Redis。执行以下命令:
$ redis-server /etc/redis.conf
这会启动 Redis 服务器进程,然后就可以使用redis了。
Windows系统
-
访问 Redis 官方网站:https://redis.io/download 。
-
在页面上选择 Stable 版本并下载最新的 Redis for Windows 版本。
-
解压下载的 Redis 软件包。你可以选择一个目录,比如
C:\Redis
,将解压后的文件放在该目录下。 -
进入 Redis 目录,在其中找到
redis.windows.conf
文件并将其重命名为redis.conf
。 -
编辑
redis.conf
文件。你可以根据需要修改一些默认配置,比如设置密码、修改监听端口等。一般情况下,你可以保留默认配置。 -
打开一个命令提示符(CMD)窗口,并导航到 Redis 目录下。
-
启动 Redis 服务器。在命令提示符窗口中运行以下命令:
redis-server.exe redis.conf
这将启动 Redis 服务器。
-
打开另一个命令提示符(CMD)窗口,并导航到 Redis 目录下。
-
启动 Redis 客户端。在命令提示符窗口中运行以下命令:
redis-cli.exe
这将启动 Redis 客户端,并连接到本地运行的 Redis 服务器。
现在你已经成功在 Windows 上安装和启动了 Redis。你可以使用 Redis 客户端执行各种 Redis 命令来管理和操作 Redis 数据库。
3.Redis的常用数据类型
-
字符串(String)
- 特点:存储一个字符串值。可以是任意类型的数据,不限于文本。是redis中最常用的数据类型
- 代码示例:
-
添加字符串、查询、追加、获取长度、判断是否存在:
# 添加字符串键值对 SET key value # 查询字符串值 GET key # 追加字符串值 APPEND key value # 获取字符串的长度 STRLEN key # 判断键是否存在 EXISTS key
使用
SET
命令可以给指定的键设置字符串值。使用GET
命令可以获取字符串键的值。APPEND
命令用于追加字符串值到指定键的值末尾。STRLEN
命令用于获取字符串键的长度。EXISTS
命令可以判断键是否存在。 -
自增、自减操作:
# 对键的值进行自增 INCR key # 对键的值进行自减 DECR key
使用
INCR
命令可以将键的值递增 1,若键不存在则创建并设置值为 1。使用DECR
命令则将键的值递减 1。 -
截取、替换字符串操作:
# 截取字符串的一部分 GETRANGE key start end # 替换字符串的一部分 SETRANGE key offset value
使用
GETRANGE
命令可以将字符串的一部分截取出来。使用SETRANGE
命令可以在指定偏移量处替换字符串的一部分。 -
设置过期时间、不存在设置操作:
# 设置键的过期时间(以秒为单位) EXPIRE key seconds # 仅当键不存在时,设置键的值 SETNX key value
使用
EXPIRE
命令可以设置键的过期时间,单位为秒。使用SETNX
命令可以在键不存在时设置键的值,若键已存在,则不进行任何操作。 -
MSET、MGET 操作:
# 设置多个键值对 MSET key1 value1 key2 value2 ... # 获取多个键的值 MGET key1 key2 ...
使用
MSET
命令可以设置多个键值对。使用MGET
命令可以获取多个键的值。 -
添加、获取对象、GETSET 操作:
# 将对象转换成 JSON 字符串,并存储到键中 SET key JSON_string # 获取键中存储的 JSON 字符串,并将其转换回对象 GET key # 设置键的新值,并返回旧值 GETSET key new_value
可以使用
SET
命令将对象转换为 JSON 字符串,并存储到键中。使用GET
命令可以获取键中存储的 JSON 字符串,并将其转换回对象。GETSET
命令可以设置键的新值,并返回
-
-
哈希(Hash)
- 特点:存储字段和对应的值的映射关系。比String更适合存储对象。
- 代码示例:
-
添加哈希、查询、查询所有、删除指定值、获取哈希长度、判断key是否存在:
# 添加哈希字段和值 HSET key field1 value1 # 查询哈希字段的值 HGET key field # 查询哈希中所有字段和值 HGETALL key # 删除哈希中的指定字段 HDEL key field # 获取哈希的长度(即字段的数量) HLEN key # 判断指定字段是否存在于哈希中 HEXISTS key field
使用
HSET
命令可以给哈希中的字段设置对应的值。使用HGET
命令可以查询哈希中某个字段的值。使用HGETALL
命令可以查询哈希中所有字段和对应的值。HDEL
命令可以删除哈希中的指定字段。HLEN
命令用于获取哈希的长度(即字段的数量)。HEXISTS
命令可以判断指定字段是否存在于哈希中。 -
获取所有键、获取所有值、给值加增量、存在不添加:
# 获取哈希中的所有字段 HKEYS key # 获取哈希中的所有值 HVALS key # 给哈希字段的值增加指定增量 HINCRBY key field increment # 仅当哈希字段不存在时,设置哈希字段的值 HSETNX key field value
使用
HKEYS
命令可以获取哈希中的所有字段(即键)。HVALS
命令用于获取哈希中的所有值。HINCRBY
命令可以给哈希字段的值增加指定的增量。HSETNX
命令仅当哈希字段不存在时设置字段的值,如果字段已存在,则不进行任何操作。
-
-
列表(List)
- 特点:存储有序的字符串元素列表。
- 实际上是一个链表,before Node after , left,right 都可以插入值
- 如果key 不存在,创建新的链表
- 如果key存在,新增内容
- 如果移除了所有值,空链表,也代表不存在!
- 在两边插入或者改动值,效率最高! 中间元素,相对来说效率会低一点~
- 消息排队!消息队列 (Lpush Rpop), 栈( Lpush Lpop)!
- 代码示例:
-
创建新链表或新增内容:
# 在链表左侧插入值 LPUSH key value # 在链表右侧插入值 RPUSH key value
如果
key
不存在,会自动创建一个新的链表,并将值插入其中。如果key
已经存在,则将新的值插入链表的左侧或右侧。 -
移除值:
# 从链表左侧移除并返回一个值 LPOP key # 从链表右侧移除并返回一个值 RPOP key
这些命令会从链表的左侧或右侧移除一个值,并将其返回。
-
检查链表是否为空:
# 获取链表的长度 LLEN key
使用
LLEN
命令可以获取链表中元素的个数。如果返回的结果为 0,则表示链表为空,也可以理解为该key
不存在。 -
消息队列是 Redis 中链表的常见应用场景之一,可以使用
LPUSH
和RPOP
命令来实现排队和出队操作。以下是一个示例:# 排队,将消息添加到队列的左侧 LPUSH message_queue "message1" LPUSH message_queue "message2" LPUSH message_queue "message3" # 出队,从队列的右侧获取消息 RPOP message_queue
这样,每次调用
RPOP
命令都可以获取到最新加入队列的消息,实现了简单的消息队列功能。类似地,如果使用LPUSH
和LPOP
命令,则可以将链表用作堆栈数据结构,实现先入后出的行为。需要注意的是,由于 Redis 使用内存存储数据,链表的长度不宜过长。当链表长度较长时,中间插入或修改元素的效率确实会相对较低,因此需要根据具体应用场景合理选择数据结构和操作方式。
-
- 特点:存储有序的字符串元素列表。
-
集合(Set)
- 特点:存储无序且唯一的字符串元素集合。可实现共同好友、共同关注等需求。
- 代码示例:
-
添加元素、查看所有元素、判断元素是否存在、查看集合长度、移除指定元素:
# 添加元素到集合 SADD key element1 element2 element3 # 查看集合中的所有元素 SMEMBERS key # 判断元素是否存在于集合中 SISMEMBER key element # 查看集合的长度 SCARD key # 移除集合中指定的元素 SREM key element
使用
SADD
命令可以向集合中添加一个或多个元素,而SMEMBERS
命令用于获取集合中的所有元素。SISMEMBER
命令可以判断某个元素是否存在于集合中,返回布尔值。SCARD
命令用于获取集合的长度(即集合中元素的数量)。SREM
命令可以从集合中移除指定的元素。 -
抽取随机元素:
# 从集合中随机返回指定数量的元素 SRANDMEMBER key [count]
使用
SRANDMEMBER
命令可以随机从集合中返回指定数量的元素,默认情况下返回一个元素。该命令不会删除集合中的元素。 -
随机删除元素、移动指定元素到新集合:
# 随机从集合中删除一个或多个元素,并返回被删除的元素 SPOP key [count] # 将指定元素从一个集合移动到另一个集合 SMOVE source_key destination_key element
SPOP
命令可以随机从集合中删除一个或多个元素,并返回被删除的元素。SMOVE
命令可以将指定的元素从一个集合移动到另一个集合。 -
差集、交集、并集操作:
# 计算多个集合的差集 SDIFF key1 key2 ... # 计算多个集合的交集 SINTER key1 key2 ... # 计算多个集合的并集 SUNION key1 key2 ...
使用
SDIFF
命令可以计算多个集合的差集,即在第一个集合中但不在其他集合中的元素。SINTER
命令可以计算多个集合的交集,即同时存在于所有集合中的元素。SUNION
命令可以计算多个集合的并集,即包含所有集合中的元素。
-
-
有序集合(Sorted Set)
- 特点:存储有序的字符串元素集合,每个元素关联一个分数用于排序。成绩表排序,工资表排序,年龄排序等需求可以用zset来实现。
- 代码示例:
-
添加元素、查询、排序查询、查询所有值包含 key:
# 添加有序集合的元素 ZADD key score1 member1 score2 member2 ... # 查询有序集合指定排名范围内的元素 ZRANGE key start stop # 按分数范围排序,查询有序集合的元素 ZRANGEBYSCORE key min max # 按分数范围排序,查询有序集合的元素(按降序) ZREVRANGE key start stop # 按分数范围排序,查询有序集合的元素,并返回每个元素的分数 ZRANGEBYSCORE key min max WITHSCORES
使用
ZADD
命令可以向有序集合添加一个或多个元素,每个元素都有一个数值(分数)来进行排序。使用ZRANGE
命令可以按照指定的排名范围查询有序集合的元素。ZRANGEBYSCORE
命令则按分数范围对有序集合进行排序,并查询符合条件的元素。ZREVRANGE
命令用于按分数范围对有序集合进行排序,并按降序查询元素。ZRANGEBYSCORE
命令的WITHSCORES
选项可以返回每个元素的分数。 -
移除元素、查看元素个数、查询指定区间内的元素个数:
# 从有序集合中移除指定的元素 ZREM key member1 member2 ... # 获取有序集合的元素个数 ZCARD key # 获取指定分数范围内的元素个数 ZCOUNT key min max
使用
ZREM
命令可以从有序集合中移除指定的元素。ZCARD
命令用于获取有序集合中元素的个数。ZCOUNT
命令可以查询有序集合中指定分数范围内的元素个数。
-
这些只是 Redis 支持的一部分数据类型和常用命令的示例,你可以根据具体需求选择合适的数据类型,并参考 Redis 官方文档或相关教程获取更多详细信息。
4.Redis事务
当涉及到 Redis 事务时,以下是一些常用的 Redis 命令和一个基本的事务示例:
- MULTI:标记事务的开始,将客户端设置为事务模式。
- EXEC:执行事务中的所有命令,并将结果返回给客户端。
- WATCH key1 key2 …:监视给定的键,如果在事务执行期间有其他客户端对这些键进行了修改,事务将被中止。
- UNWATCH:取消对所有键的监视。
- DISCARD:放弃执行事务中的所有命令,将客户端从事务模式中恢复。
- SET key value:将给定的键设置为相应的值。
- GET key:获取给定键的值。
- DEL key1 key2 …:删除给定的键及其关联的值。
- INCR key:将给定键的值增加 1。
- DECR key:将给定键的值减少 1。
- HSET key field value:给指定键的哈希表中的字段设置值。
- HGETALL key:获取指定键的哈希表中的所有字段和值。
- 以下是一个简单的 Redis 事务示例,展示了如何将多个命令封装在一个事务中:
MULTI SET key1 value1 SET key2 value2 GET key1 GET key2 EXEC
在这个示例中,首先使用 MULTI
命令标记事务的开始。然后,使用 SET
命令设置键 key1
和 key2
的值。接下来,使用 GET
命令获取 key1
和 key2
的值。最后,通过 EXEC
命令执行事务中的所有命令,并返回执行结果。
5.开发流程
编程式缓存
1.创建springboot项目,导入redis依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2.添加配置文件
#指定 Redis 服务器的主机地址,这里设置为 localhost 表示 Redis 服务器在本地。
spring.redis.host=localhost
#指定 Redis 服务器的端口号,默认为 6379。
spring.redis.port=6379
#指定要连接的 Redis 数据库索引,默认为 0。Redis 支持多个数据库,索引从 0 开始。
spring.redis.database=0
#指定连接池中的最大活跃连接数。当连接池中的连接数达到此值时,后续请求会被阻塞,直到有连接被释放。
spring.redis.jedis.pool.max-active=100
#指定获取连接的最大等待时间。当连接池中的连接已经被用完,且达到了最大活跃连接数时,后续请求会等待一定时间,超过这个时间后会抛出异常。
spring.redis.jedis.pool.max-wait=100ms
#指定连接池中的最大空闲连接数。当连接池中的空闲连接数超过此值时,多余的连接会被释放。
spring.redis.jedis.pool.max-idle=100
#指定连接池中的最小空闲连接数。当连接池中的空闲连接数低于此值时,连接池会创建新的连接
spring.redis.jedis.pool.min-idle=10
3.编写配置类
package com.blb.day06.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(factory);
// 配置序列化器
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson序列化器
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
4.使用配置类方法
public Article getArticle(Long id) {
ValueOperations<String, Object> article = redisTemplate.opsForValue();
Article atc = (Article) article.get(Article + id);
if (atc!=null){
System.out.println("返回redis缓存"+atc);
return atc;
}
Article selectById = articleMapper.selectById(id);
if (selectById!=null){
System.out.println("MySQL查到了,返回"+selectById);
article.set(Article+id,selectById);
return selectById;
}
System.out.println("MySQL没查到,无数据,返回null");
return null;
}
声明式缓存
编程式缓存使用复杂,代码侵入性高,推荐使用声明式缓存,通过注解来实现热点数据缓存
- 在启动类上添加EnableCaching注解
//启动缓存 @EnableCaching
- 配置类
@Configuration public class RedisConfig { @Bean public RedisCacheConfiguration provideRedisCacheConfiguration(){ //加载默认配置 RedisCacheConfiguration conf = RedisCacheConfiguration.defaultCacheConfig(); //返回Jackson序列化器 return conf.serializeValuesWith( RedisSerializationContext.SerializationPair .fromSerializer(new GenericJackson2JsonRedisSerializer())); } }
-
常用声明式缓存注解
@Cacheable
:声明方法的返回值应该被缓存,并且缓存的结果会被存储到缓存中。常用的属性包括:- 示例:
-
@Cacheable(value = "products", key = "#id") public Product getProductById(Long id) { // ... }
value
或cacheNames
:指定缓存的名称或缓存组。key
:指定缓存的键,用于获取和存储缓存结果。可以使用 SpEL 表达式指定键的生成规则。condition
:指定一个 SpEL 表达式,在满足表达式条件时才进行缓存。unless
:指定一个 SpEL 表达式,当表达式条件为真时,不进行缓存。-
@CachePut
:声明方法将结果存储到缓存中,无论缓存是否已存在。常用的属性与@Cacheable
相似。示例:
@CachePut(value = "products", key = "#product.id") public void saveProduct(Product product) { // ... }
-
@CacheEvict
:声明方法应该从缓存中移除一个或多个缓存项。示例:
@CacheEvict(value = "products", key = "#id") public void deleteProduct(Long id) { // ... }
value
或cacheNames
:指定要清除缓存的名称或缓存组。key
:指定要清除缓存的键,用于匹配具体的缓存项。allEntries
:设置为 true,表示清除所有缓存项。beforeInvocation
:设置为 true,表示在方法调用之前执行缓存清除操作。
-
@Caching
:将多个缓存注解应用到同一个方法上,以实现复杂的缓存行为。示例:
@Caching( cacheable = { @Cacheable(value = "products", key = "#id"), @Cacheable(value = "products", key = "'name:' + #name") }, evict = { @CacheEvict(value = "products", key = "'all'") } ) public Product getProduct(Long id, String name) { // ... }
上述注解只是 Spring Cache 中的一部分,还有其他一些注解可供使用,如 @CacheConfig
用于配置缓存的默认属性,@CacheResolver
用于自定义缓存解析器等。
请注意,具体的注解使用和属性配置可能会受到缓存框架的支持和版本的限制,建议查阅相应的文档来了解详细的用法和配置说明。
总结
总的来说,Redis简单易用,高性能,广泛应用于缓存、队列、计数器、实时更新等场景,成为了互联网领域的重要组件之一。