redis入门
redis入门
认识redis
SQL和Nosql对比:
一个是结构化的,一个是非结构化的
redis在内存中,读写速度快,适合做缓存
redis 是基于单线程的,key:value形式
redis也支持持久化
支持主从集群,分片集群
redis命令
redis数据结构介绍

redis通用命令
help [命令] : 帮助命令
keys * : 查看所有key,不建议生产模式使用,因为单线程如果使用keys a*会查询很久,redis会卡死
del key : 删除key
exists key : 判断key是否存在
expire key seconds : 设置key的过期时间
ttl key : 查看key的过期时间
String类型

常见命令:
SET key value : 设置key的值
GET key : 获取key的值
MSET key value ... : 设置多个key的值
MGET key ... : 获取多个key的值
INCR key : 将key的值增加1
DECR key : 将key的值减少1
INCRBY key increment : 将key的值增加increment
DECRBY key decrement : 将key的值减少decrement
INCRBYFLOAT key increment : 将key的值增加increment
DECRBYFLOAT key decrement : 将key的值减少decrement
SETNX key value : 设置key的值,仅当key不存在时才设置
SETEX key seconds value : 设置key的值,并设置过期时间
Key的层级格式

Hash类型

常用命令:
HSET key field value : 设置hash的值
HGET key field : 获取hash的值
HMSET key field value ... : 设置多个hash的值
HMGET key field ... : 获取多个hash的值
HGETALL key : 获取hash的所有值
HKEYS key : 获取hash的所有字段
HVALS key : 获取hash的所有值
HINCRBY key field increment : 将hash的值增加increment
HINCRBYFLOAT key field increment : 将hash的值增加increment
HSETNX key field value : 设置hash的值,仅当key不存在时才设置
List类型
Redis中的List类型与Java中的LinkedList类似,可以看做是一个双向链表结构。既可以支持正向检索和也可以支持反向检索。
特征也与LinkedList类似:
有序
元素可以重复
插入和删除快
查询速度一般
常用来存储一个有序数据,例如:朋友圈点赞列表,评论列表等。
常用命令:
LPUSH key value ... : 将value插入到key的左侧
RPUSH key value ... : 将value插入到key的右侧
LPOP key : 移除并返回key的左侧元素
RPOP key : 移除并返回key的右侧元素
LRANGE key start stop : 返回key的指定范围的元素
BLPOP和BRPOP : 与LPOP和RPOP类似,只不过在没有元素时等待指定时间,而不是直接返回nil
Set类型
Redis的set结构与Java中的Hashset类似,可以看做是一个value为null的HashMap。因为也是一个hash表,因此具备与HashSet类似的特征:
无序
元素不可重复
查找快
支持交集、并集、差集等功能
常用命令:
SADD key member ... : 向set中添加元素
SREM key member ... : 从set中移除元素
SCARD key : 获取set的大小
SMEMBERS key : 获取set中的所有元素
SISMEMBER key member : 判断元素是否在set中
SUNION key ... : 获取多个set的并集
SINTER key ... : 获取多个set的交集
SDIFF key ... : 获取多个set的差集
Sorted Set类型
Redis的sortedset是一个可排序的set集合,与Java中的Treeset有些类似,但底层数据结构却差别很大。sortedset中的每一个元素都带有一个score属性,可以基于score属性对元素排序,底层的实现是一个跳表(SkipList)加hash表。SortedSet具备下列特性:
可排序
元素不重复
查询速度快
因为SortedSet的可排序特性,经常被用来实现排行榜这样的功能。
常用命令:
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:求差集、交集、并集
Redis Java客户端
客户端对比

推荐使用lettuce
但是Jedis也要会用
Jedis快速入门
- 引入依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.0.1</version>
</dependency>- 建立连接
private Jedis jedis;
@BeforeEach
void setUp() {
// 建立连接
jedis = new Jedis("192.168.150.101", 6379);
// 设置密码
jedis.auth("123321");
// 选择库
jedis.select(0);
}
@AfterEach
void tearDown() {
// 关闭连接
jedis.close();
}- 操作
Jedis特点,方法名和redis命令基本一致
@Test
void testString() {
// 插入数据,方法名称就是redis命令名称,非常简单
String result = jedis.set("name", "张三");
System.out.println("result = " + result);
// 获取数据
String name = jedis.get("name");
System.out.println("name = " + name);
}Jedis线程池:
Jedis本身是线程不安全的,并且频繁的创建和销毁连接会有性能损耗,因此我们推荐大家使用Jedis连接池代替Jedis的直连方式。
public class JedisConnectionFactory {
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, "192.168.150.101", 6379,
1000, "123321");
}
// 获取Jedis对象
public static Jedis getJedis(){
return jedisPool.getResource();
}
}Spring Data Redis
提供了对不同Redis客户端的整合(Lettuce和Jedis)
提供了RedisTemplate统一API来操作Redis
支持Redis的发布订阅模型
支持Redis哨兵和Redis集群
支持基于Lettuce的响应式编程
支持基于JDK、JSON、字符串、Spring对象的数据序列化及反序列化
支持基于Redis的JDKCollection实现
快速入门:(最重要的在这里!!!)
SpringDataRedis中提供了RedisTemplate工具类,其中封装了各种对Redis的操作。并且将不同数据类型的操作API封装到了不同的类型中:
API 返回值类型 说明
redisTemplate.opsForValue() ValueOperations 操作String类型数据
redisTemplate.opsForHash() HashOperations 操作Hash类型数据
redisTemplate.opsForList() ListOperations 操作List类型数据
redisTemplate.opsForSet() SetOperations 操作Set类型数据
redisTemplate.opsForZSet() ZSetOperations 操作SortedSet类型数据
redisTemplate 通用的命令
- 引入依赖
<!--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: 192.168.150.101
port: 6379
password: 123321
lettuce:
pool:
max-active: 8 # 最大连接
max-idle: 8 # 最大空闲连接
min-idle: 0 # 最小空闲连接
max-wait: 100 # 连接等待时间- 注入RedisTemplate
@Autowired
private RedisTemplate redisTemplate;- 使用
@SpringBootTest
public class RedisTest {
@Autowired
private RedisTemplate redisTemplate;
@Test
void testString() {
// 插入一条string类型数据
redisTemplate.opsForValue().set("name", "李四");
// 读取一条string类型数据
Object name = redisTemplate.opsForValue().get("name");
System.out.println("name = " + name);
}
}序列化(重要!!!)
RedisTemplate可以接收任意Object作为值写入Redis,只不过写入前会把Object序列化为字节形式,默认是采用JDK序列化,得到的结果是这样的:
缺点是:
- 不可读
- 性能差
因此为了可读性和性能考虑,我们通常会自定义序列化器。
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
// 创建Template
RedisTemplate<String, Object> template = new RedisTemplate<>();
// 设置连接工厂
template.setConnectionFactory(redisConnectionFactory);
// 设置序列化工具
GenericJackson2JsonRedisSerializer jsonRedisSerializer =
new GenericJackson2JsonRedisSerializer();
// key和 hashKey采用 string序列化
template.setKeySerializer(RedisSerializer.string());
template.setHashKeySerializer(RedisSerializer.string());
// value和 hashValue采用 JSON序列化(object采用json序列化)
template.setValueSerializer(jsonRedisSerializer);
template.setHashValueSerializer(jsonRedisSerializer);
return template;
}尽管JSON的序列化方式可以满足我们的需求,但依然存在一些问题,如图:
为了在反序列化时知道对象的类型,JSON序列化器会将类的class类型写入json结果中,存入Redis,会带来额外的内存开销。
为了节省内存空间,我们并不会使用JSON序列化器来处理value,而是统一使用String序列化器,要求只能存储String类型的key和value。当需要存储Java对象时,手动完成对象的序列化和反序列化。
Spring默认提供了一个StringRedisTemplate类,它的key和value的序列化方式默认就是String方式。省去了我们自定义RedisTemplate的过程,但还是需要手动序列化和反序列化(ObjectMapper):
@Autowired
private StringRedisTemplate stringRedisTemplate;
// JSON工具
private static final ObjectMapper mapper = new ObjectMapper();
@Test
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);
}