文章目录
- 一、初识Redis
- 1.认识 Redis
- 2.Redis常见命令
- (1)Redis 数据结构介绍
- (2)Redis 通用命令
- (3)String 类型
- (4)String 类型的常见命令
- (5)Hash 类型
- (6)Hash 类型的常见命令
- (7)List 类型
- (8)List 类型的常见命令
- (9)Set 类型
- (10)Set 类型的常见命令
- (11)SortedSet 类型
- (12)SortedSet 类型的常见命令
- 3.Redis 的 Java 客户端
- (1)Jedis
- (2)Jedis 连接池
- (3)SpringDataRedis
- (4)SpringDataRedis 快速入门
- (5)SpringDataRedis 的序列化方式
一、初识Redis
1.认识 Redis
认识Redis
Redis 诞生于2009年全称是Remote Dictionary Server ,远程词典服务器,是一个基于内存的键值型NoSQL 数据库。
特征:
-
键值(key-value )型,value 支持多种不同数据结构,功能丰富
-
单线程,每个命令具备原子性
-
低延迟,速度快(基于内存、10多路复用、良好的编码)。
-
支持数据持久化
-
支持主从集群、分片集群
-
支持多语言客户端
2.Redis常见命令
(1)Redis 数据结构介绍
- Redis 是一个key-value 的数据库,key一般是String 类型,不过value 的类型多种多样
- String
- Hash
- List
- Set
- Sortedset(Zset)
- GEO
- BitMap
- HyperLog
(2)Redis 通用命令
通用指令是部分数据类型的,都可以使用的指令,常见的有:
- KEYS:查看符合模板的所有key
- DEL:删除一个指定的key
- EXISTS :判断key是否存在
- EXPIRE :给一个key设置有效期,有效期到期时该key会被自动删除
- TTL:查看一个KEY的剩余有效期
(3)String 类型
String 类型,也就是字符串类型,是Redis 中最简单的存储类型。
其value 是字符串,不过根据字符串的格式不同,又可以分为3类:
- string :普通字符串
- int:整数类型,可以做自增、自减操作
- float :浮点类型,可以做自增、自减操作
不管是哪种格式,底层都是字节数组形式存储,只不过是编码方式不同。字符串类型的最大空间不能超过512m。
(4)String 类型的常见命令
-
SET :添加或者修改已经存在的一个 String 类型的键值对。
-
GET :根据 key 获取 String 类型的 value。
-
MSET :批量添加多个 String 类型的键值对。
-
MGET :根据多个 key 获取多个 String 类型的 value。
-
INCR :让一个整型的 key 自增 1。
-
INCRBY: 让一个整型的 key 自增并指定步长,例如: incrby num 2 让 num 值自增 2。
-
INCRBYFLOAT :让一个浮点类型的数字自增并指定步长。
-
SETNX :添加一个 String 类型的键值对,前提是这个 key 不存在,否则不执行。
-
SETEX :添加一个 String 类型的键值对,并且指定有效期。
(5)Hash 类型
Hash类型,也叫散列,其value 是一个无序字典,类似于Java中的HashMap 结构。
String 结构是将对象序列化为JSON字符串后存储,当需要修改对象某个字段时很不方便:
hotel:user:1 | {name:“Jack”, age:21} |
---|---|
hotel:user:2 | {name:“Rose”, age:18} |
Hash 结构可以将对象中的每个字段独立存储,可以针对单个字段做 CRUD :
KEY | field | value |
---|---|---|
hotel:user:1 | name | jack |
age | 21 | |
hotel:user:2 | name | Rose |
age | 18 |
(6)Hash 类型的常见命令
-
HSET key field value :添加或者修改 hash 类型 key 的 field 的值。
-
HGET key field :获取一个 hash 类型 key 的 field 的值
-
HMSET :批量添加多个 hash 类型 key 的 field 的值
-
HMGET :批量获取多个 hash 类型 key 的 field 的值
-
HGETALL :获取一个 hash 类型的 key 中的所有的 field 和 value
-
HKEYS :获取一个 hash 类型的 key 中的所有的 field
-
HVALS :获取一个 hash 类型的 key 中的所有的 value
-
HINCRBY: 让一个 hash 类型 key 的字段值自增并指定步长
-
HSETNX :添加一个 hash 类型的 key 的 field 值,前提是这个 field 不存在,否则不执行
(7)List 类型
Redis 中的List类型与Java中的LinkedList 类似,可以看做是一个双向链表结构。既可以支持正向检索和也可以支持反向检索。
特征也与LinkedList 类似:
- 有序
- 元素可以重复
- 插入和删除快
- 查询速度一般
常用来存储一个有序数据,例如:朋友圈点赞列表,评论列表等。
(8)List 类型的常见命令
- LPUSH key element … :向列表左侧插入一个或多个元素
- LPOP key :移除并返回列表左侧的第一个元素,没有则返回 nil
- RPUSH key element … :向列表右侧插入一个或多个元素
- RPOP key :移除并返回列表右侧的第一个元素
- LRANGE key star end :返回一段角标范围内的所有元素
- BLPOP 和 BRPOP :与 LPOP 和 RPOP 类似,只不过在没有元素时等待指定时间,而不是直接返回 nil
(9)Set 类型
Redis 的Set结构与Java中的HashSet 类似,可以看做是一个value 为null的HashMap 。因为也是一个hash表,因此具备与HashSet 类似的特征:
- 无序
- 元素不可重复
- 查找快
- 支持交集、并集、差集等功能
(10)Set 类型的常见命令
-
SADD key member … :向 set 中添加一个或多个元素
-
SREM key member … : 移除 set 中的指定元素
-
SCARD key : 返回 set 中元素的个数
-
SISMEMBER key member :判断一个元素是否存在于 set 中
-
SMEMBERS :获取 set 中的所有元素
-
SINTER key1 key2 … :求 key1 与 key2 的交集
-
SDIFF key1 key2 … :求 key1 与 key2 的差集
-
SUNION key1 key2 … :求 key1 和 key2 的并集
(11)SortedSet 类型
Redis 的Sortedset 是一个可排序的set集合,与java中的TreeSet 有些类似,但底层数据结构却差别很大。Sortedset 中的每一个元素都带有一个score 属性,可以基于score 属性对元素排序,底层的实现是一个跳表(SkipList )加hash表。
SortedSet 具备下列特性:
- 可排序
- 元素不重复
- 查询速度快
因为SortedSet 的可排序特性,经常被用来实现排行榜这样的功能。
(12)SortedSet 类型的常见命令
ZADD key score member :添加一个或多个元素到 sorted set ,如果已经存在则更新其 score 值
- ZREM key member :删除 sorted set 中的一个指定元素
- ZSCORE key member : 获取 sorted set 中的指定元素的 score 值
- ZRANK key member :获取 sorted set 中的指定元素的排名
- ZCARD key :获取 sorted set 中的元素个数
- ZCOUNT key min max :统计 score 值在给定范围内的所有元素的个数
- ZINCRBY key increment member :让 sorted set 中的指定元素自增,步长为指定的 increment 值
- ZRANGE key min max :按照 score 排序后,获取指定排名范围内的元素
- ZRANGEBYSCORE key min max :按照 score 排序后,获取指定 score 范围内的元素
- ZDIFF 、 ZINTER 、 ZUNION :求差集、交集、并集
注意:所有的排名默认都是升序,如果要降序则在命令的 Z 后面添加 REV 即可
3.Redis 的 Java 客户端
在 Redis 官网中提供了各种语言的客户端,地址: https://redis.io/clients
(1)Jedis
jedis官网https://github.com/redis/jedis
- 引入依赖:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.7.0</version>
</dependency>
- 创建 Jedis 对象,建立连接:
public Jedis setUp() {
//建立连接
Jedis jedis = new Jedis("127.0.0.1", 6379);
//选择库
jedis.select(0);
return jedis;
}
- 使用 Jedis ,方法名与 Redis 命令一致:
@Test
public void testString() {
Jedis jedis = setUp();
try {
//插入数据,方法名称就是 redis命令名称,非常简单
String result = jedis.set("name", " 张三 ");
System.out.println("result = " + result);
//获取数据
String name = jedis.get("name");
System.out.println("name = " + name);
} finally {
jedis.close();
}
}
(2)Jedis 连接池
Jedis 本身是线程不安全的,并且频繁的创建和销毁连接会有性能损耗,因此我们推荐大家使用Jedis 连接池代替Jedis 的直连。
private static final JedisPool jedisPool;
static {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
//最大连接
jedisPoolConfig.setMaxTotal(8);
//最大空闲连接
jedisPoolConfig.setMaxIdle(8);
//最小空闲连接
jedisPoolConfig.setMinIdle(0);
//设置最长等待时间, ms
jedisPoolConfig.setMaxWaitMillis(200);
jedisPool = new JedisPool(jedisPoolConfig, "127.0.0.1", 6379,
1000);
}
//获取 Jedis对象
public static Jedis getJedis() {
return jedisPool.getResource();
}
(3)SpringDataRedis
SpringData 是Spring 中数据操作的模块,包含对各种数据库的集成,
其中对Redis 的集成模块就叫做Spring DataRedis ,官网地址:https://spring.io/projects/spring-data-redis/
提供了对不同 Redis 客户端的整合( Lettuce 和 Jedis )
- 提供了 RedisTemplate 统一 API 来操作 Redis
- 支持 Redis 的发布订阅模型
- 支持 Redis 哨兵和 Redis 集群
- 支持基于 Lettuce 的响应式编程
- 支持基于 JDK 、 JSON 、字符串、 Spring 对象的数据序列化及反序列化
- 支持基于 Redis 的 JDKCollection 实现
(4)SpringDataRedis 快速入门
SpringDataRedis 中提供了 RedisTemplate 工具类,其中封装了各种对 Redis 的操作。并且将不同数据类型的操作
API 封装到了不同的类型中:
- 引入依赖:
<!--Redis依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--连接池依赖 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
- 配置文件:
spring:
redis:
host: 127.0.0.1
port: 6379
lettuce:
pool:
max-active: 8 #最大连接
max-idle: 8 #最大空闲连接
min-idle: 0 #最小空闲连接
max-wait: 100 #连接等待时间
- 编写测试
@Autowired
private RedisTemplate redisTemplate;
@Test
public void testString() {
//插入一条 string类型数据
redisTemplate.opsForValue().set("name", " 李四 ");
//读取一条 string类型数据
Object name = redisTemplate.opsForValue().get("name");
System.out.println("name = " + name);
}
(5)SpringDataRedis 的序列化方式
RedisTemplate 可以接收任意 Object 作为值写入 Redis ,只不过写入前会把 Object 序列化为字节形式,默认是采用 JDK 序列化,得到的结果是这样的:
缺点:
- 可读性差
- 内存占用较大
我们可以自定义 RedisTemplate 的序列化方式,代码如下:
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
//创建 Template
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
//设置连接工厂
redisTemplate.setConnectionFactory(redisConnectionFactory);
//设置序列化工具
GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
// key和 hashKey采用 string序列化
redisTemplate.setKeySerializer(RedisSerializer.string());
redisTemplate.setHashKeySerializer(RedisSerializer.string());
// value和 hashValue采用 JSON序列化
redisTemplate.setValueSerializer(jsonRedisSerializer);
redisTemplate.setHashValueSerializer(jsonRedisSerializer);
return redisTemplate;
}
尽管 JSON 的序列化方式可以满足我们的需求,但依然存在一些问题,如图:
为了在反序列化时知道对象的类型, JSON 序列化器会将类的 class 类型写入 json 结果中,存入 Redis ,会带来额外的内存开销。
为了节省内存空间,我们并不会使用 JSON 序列化器来处理 value ,而是统一使用 String 序列化器,要求只能存储String 类型的 key 和 value 。当需要存储 Java 对象时,手动完成对象的序列化和反序列化。
Spring 默认提供了一个 StringRedisTemplate 类,它的 key 和 value 的序列化方式默认就是 String 方式。省去了我们自定义 RedisTemplate 的过程:
@Autowired(required = false)
private StringRedisTemplate stringRedisTemplate;
// JSON工具
private static final ObjectMapper mapper = new ObjectMapper();
@Test
public void testStringTemplate() throws JsonProcessingException {
//准备对象
User user = new User(" 虎哥 ", 18);
//手动序列化
String json = mapper.writeValueAsString(user);
//写入一条数据到 redis
stringRedisTemplate.opsForValue().set("user:200", json);
//读取数据
String val = stringRedisTemplate.opsForValue().get("user:200");
//反序列化
User user1 = mapper.readValue(val, User.class);
System.out.println("user1 = " + user1);
}