文章目录
Redis
redis是一个开源的、使用C语言编写的、支持网络交互的、可基于内存也可持久化的Key-Value数据库。与传统数据库不同的是 redis 的数据是存在内存中的,所以读写速度非常快,因此 redis 被广泛应用于缓存方向。另外,redis 也经常用来做分布式锁。
redis安装后,在src和/usr/local/bin下有几个以redis开头的可执行文件,称为redis shell。
Redis执行命令 | 说明 |
---|---|
redis-server | 启动redis |
redis-cli | redis命令行工具 |
redis-benchmark | 基准测试工具 |
redis-check-aof | AOF持久化文件检测工具和修复工具 |
redis-check-dump | RDB持久化文件检测工具和修复工具 |
redis-sentinel | 启动redis-sentinel |
简述Redis的运行速度为何快?
- 基于内存操作,手动持久化到硬盘
- 高效数据结构,数据操作简单
- 单线程,避开多线程上下文切换的操作
- 多路I/O复用模型,非阻塞I/O
- 底层模型不同,底层实现方式及与客户端之间通信的应用协议不一样
- Redis直接自己构建了VM 机制 ,一般系统调用函数会浪费时间移动和请求
(一)五大数据类型
1、String-字符串
String的数据结构为简单动态字符串。是可以修改的字符串,内部结构实现上类似于Java的ArrayList,最大value值为512M,可以包含任何数据,比如jpg图片(生成二进制)或者序列化的对象。
-
应用场景:计数场景,用户的访问次数、热点文章的点赞转发数量。
-
常用命令:
set,get,strlen,exists,dect,incr,setex
-
set
设置键值,使用get
获取,使用getset
命令获取当前键值并更新value值127.0.0.1:6379> set name zhangsan OK 127.0.0.1:6379> get name "zhangsan" 127.0.0.1:6379> getset name lisi "zhangsan" 127.0.0.1:6379> get name "lisi"
-
strlen
命令可获得当前键值对应value值的字节长度127.0.0.1:6379> strlen name (integer) 4
-
incr
命令可将 key 中储存的数字值增一,incrby
命令可将 key 中储存的数字增加任意数值127.0.0.1:6379> incr id (integer) 57 127.0.0.1:6379> incrby id 10 (integer) 67
-
decr
命令可将 key 中储存的数字值减一,decrby
命令可将 key 中储存的数字减少任意数值127.0.0.1:6379> decr id (integer) 66 127.0.0.1:6379> decr by id (integer) 56
-
exists
命令用于检查给定 key 是否存在,存在为1,不存在为0.127.0.0.1:6379> exists name (integer) 1 127.0.0.1:6379> exists na (integer) 0
-
setex
为指定的 key 设置值及其过期时间,ttl
命令查看当前时间127.0.0.1:6379> setex name 20 zhangsan OK 127.0.0.1:6379> get name "zhangsan" 127.0.0.1:6379> ttl name (integer) 11 127.0.0.1:6379> ttl name (integer) 3 127.0.0.1:6379> get name (nil)
-
setnx
在指定的 key 不存在时,为 key 设置指定的值。127.0.0.1:6379> setnx name lisi (integer) 1 127.0.0.1:6379> setnx name liwu (integer) 0
-
mset
命令设置多个键值对,mget
命令取多个键值。127.0.0.1:6379> mset name lisi sex nan OK 127.0.0.1:6379> mget name sex 1) "lisi" 2) "nan"
-
append
命令追加value值。127.0.0.1:6379> append name 123456789 (integer) 13 127.0.0.1:6379> get name "lisi123456789"
-
2、List-列表
链表是一种非常常见的数据结构,特点是易于数据元素的插入和删除并且且可以灵活调整链表长度,但是链表的随机访问困难。一个存储空间保存多个数据,且通过数据可以体现进入顺序。
-
应用场景: 发布与订阅、消息队列、慢查询。
-
常用命令:
rpush,lpop,lpush,rpop,lrange、llen
-
rpush
添加一个或多个值、lpush
在头部添加一个或多个值。127.0.0.1:6379> lpush people lida wanger zhangsan (integer) 3 127.0.0.1:6379> rpush people liqi wangba zhangjiu (integer) 6
-
lindex
获得指定索引的元素,lrange
获取指定范围的元素。127.0.0.1:6379> lindex people 2 "lida" 127.0.0.1:6379> lrange people 0 2 1) "zhangsan" 2) "wanger" 3) "lida"
-
lpop
移出并获取列表的第一个元素、rpop
移除并获取列表最后一个元素。127.0.0.1:6379> lpop people "zhangsan" 127.0.0.1:6379> rpop people "zhangjiu" 127.0.0.1:6379>
-
llen
获取当前长度127.0.0.1:6379> llen people (integer) 4
-
lrem
移除列表元素127.0.0.1:6379> lrem people 1 wanger (integer) 1 127.0.0.1:6379> lrange people 0 5 1) "lida" 2) "liqi" 3) "wangba"
-
ltrim
保留指定区间内的元素,移除其他所有元素127.0.0.1:6379> ltrim people 1 4 OK 127.0.0.1:6379> lrange people 0 10 1) "wanger" 2) "lisi" 3) "zhangsan" 4) "lida"
-
linsert
在列表的元素前或者后插入元素127.0.0.1:6379> linsert people before lisi lier (integer) 5 127.0.0.1:6379> lrange people 0 10 1) "wanger" 2) "lier" 3) "lisi" 4) "zhangsan" 5) "lida"
-
3、Hash-哈希
hash 类似于 JDK1.8 前的 HashMap,内部实现也差不多(数组 + 链表)。
hash 是一个 string 类型的 field 和 value 的映射表,特别适合用于存储对象,后续操作的时候,你可以直接仅仅修改这个对象中的某个字段的值。
-
应用场景:对象数据存储、电商网站购物车设计与实现。
-
常用命令:
hset,hmset,hexists,hget,hgetall,hkeys,hvals
-
hset
将哈希表 key 中的字段 field 的值设为 value 。hget
获取存储在哈希表中指定字段的值。127.0.0.1:6379> hset student name lisi (integer) 0 127.0.0.1:6379> hget student name "lisi"
-
hmset
将多个 field-value (域-值)对设置到哈希表 key 中、hmget
获取所有给定字段的值。127.0.0.1:6379> hmset student name zhangsan age 24 sex nan OK 127.0.0.1:6379> hmget student name age sex 1) "zhangsan" 2) "24" 3) "nan"
-
hkeys
获取所有哈希表中的字段、hvals
获取哈希表中所有值、hgetall
获取所有字段和值127.0.0.1:6379> hkeys student 1) "name" 2) "age" 3) "sex" 127.0.0.1:6379> hvals student 1) "wangwu" 2) "24" 3) "nan" 127.0.0.1:6379> hgetall student 1) "name" 2) "wangwu" 3) "age" 4) "24" 5) "sex" 6) "nan"
-
hexists
查看哈希表 key 中,指定的字段是否存在。hlen
获取哈希表中字段的数量127.0.0.1:6379> hexists student sex (integer) 1 127.0.0.1:6379> hexists studeng gils (integer) 0 127.0.0.1:6379> hlen student (integer) 3
-
hdel
删除一个或多个哈希表字段127.0.0.1:6379> hdel student name (integer) 1 127.0.0.1:6379> hgetall student 1) "age" 2) "24" 3) "sex" 4) "nan"
-
4、Set-无序集合
set 类似于 Java 中的 HashSet 。
Redis 中的 set 类型是一种无序集合,集合中的元素没有先后顺序。 set 提供了判断某个成员是否在一个 set 集合内的重要接口,这个也是 list 所不能提供的。可以基于 set 轻易实现交集、并集、差集的操作。
-
应用场景:存放不重复的数据、获取多个数据源交集、并集和差集、共同喜爱、共同粉丝。
-
常用命令:
sadd,spop,smembers,sismember,scard,sinterstore,sunion
-
sadd
向集合添加一个或多个成员、smembers
返回集合中的所有成员、srem
移除集合中一个或多个成员127.0.0.1:6379> smembers friends:1 1) "1" 2) "3" 3) "5" 4) "7" 127.0.0.1:6379> smembers friends:2 1) "1" 2) "2" 3) "5" 4) "9" 5) "10" 127.0.0.1:6379> sadd friends:1 1 3 5 7 9 (integer) 5 127.0.0.1:6379> sadd friends:2 1 5 9 10 2 (integer) 5 127.0.0.1:6379> smembers friends:1 1) "1" 2) "3" 3) "5" 4) "7" 5) "9" 127.0.0.1:6379> srem friends:1 3 5 (integer) 2 127.0.0.1:6379> smembers friends:1 1) "1" 2) "7" 3) "9"
-
sismeber
判断元素是否是集合 key 的成员,scard
获取集合的成员数127.0.0.1:6379> sismember friends:1 3 (integer) 1 127.0.0.1:6379> sismember friends:1 2 (integer) 0 127.0.0.1:6379> scard friends:2 (integer) 5
-
srandmember
返回集合中一个或多个随机数、spop
移除并返回集合中的一个随机元素127.0.0.1:6379> srandmember friends:2 "5" 127.0.0.1:6379> srandmember friends:2 "1" 127.0.0.1:6379> spop friends:1 "9" 127.0.0.1:6379> smembers friends:1 1) "1" 2) "7"
-
sinter
集合的交集、sunion
集合的并集,sdiff
集合的差集(以前集合为准)127.0.0.1:6379> sinter friends:1 friends:2 1) "1" 2) "5" 127.0.0.1:6379> sunion friends:1 friends:2 1) "1" 2) "2" 3) "3" 4) "5" 5) "7" 6) "9" 7) "10" 127.0.0.1:6379> sdiff friends:1 friends:2 1) "3" 2) "7"
-
5、Zset-有序集合
Zset 增加了一个权重参数 score,使得集合中的元素能够按 score 进行有序排列,还可以通过 score 的范围来获取元素的列表。类似 Java 中 HashMap 和 TreeSet 的结合体。
根据评分( score )或者次序( position )来获取一个范围的元素。访问中间元素快。
-
应用场景:数据根据某个权重排序、直播系统中的实时排行信息、直播间在线用户列表,礼物排行榜,弹幕消息、会员短期体验之过期失效。
-
常用命令:
zadd,zcard,zscore,zrange,zrevrange,zrem
-
zadd
向有序集合添加一个或多个成员,或者更新已存在成员的分数。127.0.0.1:6379> zadd hot:note 55 1 44 2 33 3 22 4 11 5 1 6 (integer) 6
-
zcard
成员数、zcount
指定区间分数的成员数、zscore
成员的分数值127.0.0.1:6379> zcard hot:note (integer) 6 127.0.0.1:6379> zcount hot:note 10 30 (integer) 2 127.0.0.1:6379> zscore hot:note 3 "33"
-
zrange
通过索引区间返回有序集合成指定区间内的成员,zrevrange
分数从高到底127.0.0.1:6379> zrange hot:note 0 4 1) "6" 2) "5" 3) "4" 4) "3" 5) "2" 127.0.0.1:6379> zrevrange hot:note 0 4 1) "1" 2) "2" 3) "3" 4) "4" 5) "5"
-
zrem
移除有序集合中的一个或多个成员、127.0.0.1:6379> zrem hot:note 2 (integer) 1
-
(二)整合spring缓存注解及属性
@Cacheable | 方法的返回值将被缓存,类上说明所有方法返回值存入缓存。 |
---|---|
value / cacheNames | 指定缓存组件的名称 |
key / keyGenerator | 指定缓存数据所使用的的 key值 |
cacheManager / cacheResolver | 指定缓存管理器 |
condition | 判断属性,用来指定符合指定的条件下才可以缓存 |
unless | 指定的条件为 true 时,方法的返回值才不会被缓存。 |
sync | 指定是否使用异步模式,默认 false为同步模式。 |
@CacheEvict | 用来标注在需要清除缓存元素的方法或类上的 |
---|---|
key | 指定缓存数据所使用的的 key值 |
value | 找到相同名称更新缓存数据,如没有相同,重新写入缓存 |
condition | 符合指定的条件下为true才可以缓存 |
allEntries | 将这个缓存中的数据全部删除 |
beforeInvocation | 缓存的清除是否在方法之前执行,默认代表在方法执行之后执行。 |
@CachePut | 确保添加注解的方法会执行,并将改变的数据写入缓存 |
---|---|
key | 指定缓存数据所使用的的 key值 |
value | 找到相同名称更新缓存数据,如没有相同,重新写入缓存 |
condition | 符合指定的条件下为true才可以缓存 |
(三)快速使用
1、配置依赖
<!--redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2、配置环境
#配置redis
spring.redis.host=localhost
spring.redis.port=6379
#连接超时5s 单位毫秒ms
spring.redis.timeout=5000
3、测试运行
@SpringBootTest
public class RedisTest {
@Resource
private RedisTemplate<String, String> redisTemplate;
@Test
public void testRedis() {
redisTemplate.opsForValue().set("test", "test2");
System.out.println(redisTemplate.opsForValue().get("test"));
}
}
出现如下结果代表测试运行成功
4、Redis配置类(序列化)
默认序列化方式为JdkSerializationRedisSerializer, ISO-8859-1编码,在其他平台出现乱码问题;配置StringRedisSerializer序列化方式,其编码为 UTF-8,可以解决任意平台的乱码问题。
-
@EnableCaching代表注解驱动的缓存管理功能。
-
@Configuration将配置的组件添加到spring容器中。
@Configuration
@EnableCaching
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);
//["com.wanmait.demo.pojo.QuestionType",{"id":1,"title":"测试","questionCount":null,"sort":null,"enable":null,"info":null}]
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
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;
}
}
5、业务逻辑层
- 在类上添加注解
@CacheConfig
代表此类下的所有方法有返回值时会存储进Redis缓存中。 cacheNamess
属性代表此类下所有缓存数据均以此属性作为父名称。@Cacheable
带有属性时指定缓存数据所使用的的 key值,不带属性时不指定。@CacheEvict
清除缓存,allEntries=true
属性代表全部清除。@CachePut
因为用list类型的存缓存,不推荐用@cachePut来更新缓存。
@Service
@CacheConfig(cacheNames = {" users "})
public class UserService implements UserMapper {
@Autowired
private UserMapper userMapper;
@Override
@Cacheable
public List<User> findAllUser() {
return userMapper.findAllUser();
}
@Override
@Cacheable(key = "#id")
public User findUserById(Long id) {
return userMapper.findUserById(id);
}
@Override
public void insertUser(User user) {
userMapper.insertUser(user);
}
@Override
@CacheEvict(key = "#id",allEntries = true)
public void deleteUser(Long id) {
userMapper.deleteUser(id);
}
@Override
//@CachePut(key = "#user.id", unless = "#result == null")
public void updateUser(User user) {
userMapper.updateUser(user);
}
@Override
@Cacheable
public List<User> findUser() {
return userMapper.findUser();
}
}
6、测试工具检验
使用前端API测试工具发送请求,在Redis Desktop Manager可视化工具查看,如结果如下,说明缓存正常使用。