Redis学习笔记

发布于:2025-07-22 ⋅ 阅读:(15) ⋅ 点赞:(0)

目录

一、认识NoSQL及Redis

二、通用命令

三、数据结构-基本类型

1、String类型-字符串类型

2、Hash类型 

3、List类型

 4、Set类型

​编辑 5、SortedSet类型

四、Redis的Java客户端-Jedis

五、Redis的Java客户端-lettuce(Spring Data Redis包含该客户端) 

六、Redis的Java客户端-Redisson

七、SpringDataRedis

1、gradle引入依赖

2、配置application.yml

3、方式一:使用RedisTemplate工具类,需要自定义RedisTemplate处理序列化

4、方式二:StringRedisTemplate类,存储java对象时,需手动完成对象的序列化和反序列化


一、认识NoSQL及Redis

1、SQL与NoSQL对比

SQL:数据结构化并且是关联的,使用SQL查询,事务特性ACID,磁盘存储,垂直扩展
使用场景:数据结构固定,相关业务对数据安全性、一致性要求较高

NoSQL:数据非结构化并且无关联,非SQL查询,事务特性BASE,内存存储,水平扩展
使用场景:数据结构不固定,对一致性、安全性要求不高,对性能要求

2、认识Redis

Redis诞生于2009年,全称是Remote Dictionary Server,远程词典服务器,是一个基于内存的键值型NoSQL数据库。

特征:
键值(key-value)型,value支持多种不同数据结构,功能丰富
单线程,每个命令具备原子性
低延迟,速度快(基于内存、IO多路复用、良好的编码)
支持数据持久化
支持主从集群、分片集群
支持多语言客户端

3、key结构

Redis的key允许有多个单词形成层级结构,多个单词之间用':'隔开

格式示例:
项目名:业务名:类型:id
二、通用命令
# 输入ip端口密码连接redis
redis-cli -h 192.168.1.104 -p 6379 -a 123456

# 输入ip端口连接redis
redis-cli -h 192.168.1.104 -p 6379
# 输入密码进入redis
AUTH 123456

# 切换到数据库1
select 1

# 查询所有key,不建议在生产环境设备上使用
keys *

# 查询所有带a的key,不建议在生产环境设备上使用
key a*

# 设置一个key为name,值为张三的数据 返回OK代表成功
set name '张三'

# 同时设置多个key,返回OK代表成功
mset k1 v1 k2 v2

# 删除一个key为name的数据 返回删除成功的个数 支持多个key,空格隔开
del name
del k1 k2 # 删除多个

# 判断key为k1,k2的数据是否存在,不存在返回0,存在则返回存在个数
exists k1 k2

# 设置k1在500秒后过期 返回"1"代表成功
expire k1 500

# 查看k1的有效时间 返回秒数 -1为永久有效 -2为已过期
ttl k1
三、数据结构-基本类型
1、String类型-字符串类型
Value是字符串,根据格式不同分为3类:
string:普通字符串
int:整数类型,可以做自增、自减操作
float:浮点类型,可以做自增、自减操作

不管是哪种格式,底层都是字节数组形式存储,只不过是编码方式不同。字符串类型的最大空间不能超过512m.

示例:
# 添加/修改一个String类型键值对 返回OK
set msg "hello world"

# 设置msg在500秒后过期 返回"1"代表成功
expire msg 500

# 批量添加多个String类型键值对 返回OK
mset num 11 score 93.5

# 根据key获取String类型的value,返回"hello world"
get msg

# 根据多个key获取多个String类型的值 返回 1) "11" 2) "93.5"
mget num score 

# 让一个整型的key自增1 返回"12"
incr num 

# 让一个整型的key自增并指定步长 返回 "14"
incrby num 2 

# 让一个浮点类型的数字自增并指定步长 返回 "95.599999999999994"
incrbyfloat score 2.1

# 添加一个String类型的键值对,前提是这个key不存在,否则不执行
setnx msg "test" # 存在msg,未设置成功,返回"0"
setnx test "test" # 不存在test,设置成功,返回"1"

# 添加一个String类型的键值对,并且指定有效期
setex test 100 "test1" # 重置test键的值并设置100秒后过期
ttl test # 查看test过期秒数

2、Hash类型 
Hash类型,也叫散列,其value是一个无序字典,类似于Java中的HashMap结构。
String结构是将对象序列化为JSON字符串后存储,当需要修改对象某个字段时很不方便;
Hash结构可以将对象中的每个字段独立存储,可以针对单个字段做CRUD

示例(key为sample:hs:score):
# 添加/修改hash类型key的field值 返回"1"
hset sample:hs:score "张三" 59

# 设置sample:hs:score在500秒后过期 返回"1"代表成功
expire sample:hs:score 500

# 批量添加多个hash类型key的field的值 返回 "OK"
hmset sample:hs:score "李四" 61 "王五" 60

# 获取一个hash类型key的field的值 返回 "59"
hget sample:hs:score "张三"

# 批量获取多个hash类型key的field的值 返回 1) "61" 2) "60"
hmget sample:hs:score "李四" "王五"

# 获取一个hash类型的key中的所有的field和value
# 返回 1) "张三" 2) "59" 3) "李四" 4) "61" 5) "王五" 6) "60"
hgetAll sample:hs:score

# 获取一个hash类型的key中的所有的field 返回 1) "张三" 2) "李四" 3) "王五"
hkeys sample:hs:score

# 获取一个hash类型的key中的所有的value 返回 1) "59" 2) "61" 3) "60"
hvals sample:hs:score

# 让一个hash类型key的字段值自增并指定步长 返回 "69"
hincrby sample:hs:score "张三" 10

# 添加一个hash类型的key的field值,前提是这个field不存在,否则不执行
hsetnx sample:hs:score "张三" 50 # 存在,未设置成功,返回 "0"
hsetnx sample:hs:score "赵六" 50 # 不存在,设置成功,返回 "1"

3、List类型
Redis中的List类型与Java中的LinkedList类似,可以看作是一个双向链表结构。既可以支持正向检索和也可以支持反向检索。
特征:有序、元素可以重复、插入和删除快、查询速度一般
常用来存储一个有序数据,例如:朋友圈点赞列表,评论列表等。

示例:
# 向列表左侧插入一个或多个元素,row=1 value=b 最后插入的元素在最前面
lpush sample:comment "a" "b"

# 设置sample:comment在500秒后过期 返回"1"代表成功
expire sample:comment 500

# 移除并返回列表左侧的第一个元素,没有则返回null
lpop sample:comment # 返回"b"

# 向列表右侧插入一个或多个元素,row=1 value=a 最后插入的元素在最后面
rpush sample:comment "a" "b"

# 移除并返回列表右侧的第一个元素,返回"b"
rpop sample:comment

# 返回一段角标范围内的所有元素,不包含起始下标值 返回 1) "b"
lrange sample:comment 1 2 

# 与lpop和rpop类似,只不过在没有元素时等待指定时间,而不是直接返回null
# 有值时返回 1) "sample:comment" 2) "b",无值等待10秒返回空白
blpop sample:comment 10 
brpop sample:comment 10

 4、Set类型
Reids的Set结构与Java中的HashSet类似,可以看作是一个value为null的HashMap。因为也是一个hash表,因此具备与HashSet类似的特征:无序、元素不可重复、查找快、支持交集/并集/差集等功能。

示例:
# 向set中添加一个或多个元素
sadd sample:rank 6 7 8

# 设置sample:rank在500秒后过期 返回"1"代表成功
expire sample:rank 500

# 移除set中的指定元素 返回"1"代表成功
srem sample:rank 7

# 返回set中元素的个数 返回"2"
scard sample:rank

# 判断一个元素是否存在于set中
sismember sample:rank  8 # 存在,返回"1" 
sismember sample:rank  7 # 不存在,返回"0"

# 获取set中的所有元素 返回 1)  "6" 2)  "8"
smembers sample:rank
 5、SortedSet类型
Redis的SortedSet是一个可排序的set集合,与Java中的TreeSet有些类似,但底层数据结构却差别很大。SortedSet中的每一个元素都带有一个score属性,可以基于score属性对元素排序,底层的实现是一个跳表(SkipList)加hash表。
特性:可排序、元素不重复、查询速度快
因为SortedSet的可排序特性,经常被用来实现排行榜这样的功能。

示例(排名默认升序,降序在命令z后面加rev即可):
# 添加一个或多个元素到sorted set,如果已经存在则更新其score值
# 新增行返回"1" 修改行返回"0"
zadd sample:goldRank 101 "张三" 200 "李四" 150 "王五" 

# 设置sample:rank在500秒后过期 返回"1"代表成功
expire sample:goldRank 500

# 删除sorted set中的一个指定元素 返回"1"代表成功 返回"0"代表不存在
zrem sample:goldRank "王五"

# 获取sorted set中的指定元素的score值 返回"200"
zscore sample:goldRank "李四"

# 获取sorted set中指定元素的排名 张三 201 李四 200
zrank sample:goldRank "张三" # 返回"1"
zrevrank sample:goldRank "张三" # 返回"0"

# 获取sorted set中的元素个数 返回"2"
zcard sample:goldRank

# 统计score值在给定范围内的所有元素的个数 返回"1"
zcount sample:goldRank 200 500

# 让sorted set中的指定元素自增,步长为100 返回"201"
zincrby sample:goldRank 100 "张三" 

# 按照score排序后,获取指定排名范围内的元素,排名从0开始,0为最小值 返回 1) "张三"
zrange sample:goldRank 1 10

# 获取指定排名范围内的元素及score 返回 1) "张三" 2) "201"
zrange sample:goldRank 1 10 withscores

# 按照score排序后,获取指定score范围内的元素
zrangebyscore sample:goldRank (200 (500 # 200<score<500 返回 1) "张三"
zrangebyscore sample:goldRank (200 500 # 200<score<=500 返回 1) "张三"
zrangebyscore sample:goldRank 200 500 # 200<=score<=500 返回 1) "李四" 2) "张三"
zrangebyscore sample:goldRank -inf +inf # 显示所有数据 返回 1) "李四" 2) "张三"

# score<=200,并返回score 返回 1) "李四"2) "200"
zrangebyscore sample:goldRank -inf 200 withscores

# 求差集、交集、并集
zdiff zinter zunion

四、Redis的Java客户端-Jedis
以Reids命令作为方法名称,学习成本低,简单实用,
但是Jedis实例是线程不安全的,多线程环境下需要基于连接池来使用。
Spring Data Redis包含该客户端

1、推荐使用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);  
		//注意没密码不要设置为"",会auth报错
		jedisPool = new JedisPool(jedisPoolConfig, "192.168.10.104", 6379, 1000);  
	}  
	  
	/**  
	* 获取Jedis对象  
	*  
	* @return  
	*/  
	public static Jedis getJedis() {  
		return jedisPool.getResource();  
	}  
}

2、gradle引入依赖

implementation 'redis.clients:jedis:5.1.2'
implementation 'org.apache.commons:commons-pool2:2.10.0'

 3、示例junit测试代码

@SpringBootTest  
public class JedisApplicationTests {  
	private Jedis jedis;  
	  
	@BeforeEach  
	void setUp() {  
		//jedis直连  
		//jedis = new Jedis("192.168.10.104", 6379);  
		//有密码需设置  
		//jedis.auth("");  
		  
		//使用jedis连接池  
		jedis = JedisConnectionFactory.getJedis();  
		jedis.select(1);
	}  
	  
	@Test  
	void testString() {  
		//设置STRING类型数据  
		String result = jedis.set("name1", "张三");  
		System.out.println("result=" + result);  
		  
		//设置500秒过期  
		jedis.expire("name1", 500);  
		  
		//根据key获取value  
		String name = jedis.get("name1");  
		System.out.println("name=" + name);  
	}  
	  
	@Test  
	void testHash() {  
		//创建hash并添加键值对  
		jedis.hset("sample:hs:score", "张三", "100");  
		  
		//设置500秒过期  
		jedis.expire("sample:hs:score", 500);  
		  
		//追加键值对到hash  
		HashMap<String, String> map = new HashMap<>();  
		map.put("李四", "200");  
		map.put("王五", "150");  
		jedis.hmset("sample:hs:score", map);  
		  
		//获取hash所有键值对  
		Map<String, String> m = jedis.hgetAll("sample:hs:score");  
		System.out.println(m.toString());  
	}  
	  
	@Test  
	void testList() {  
		//创建list并插入数据  
		jedis.lpush("sample:comment", "a", "b");  
		jedis.rpush("sample:comment", "c", "d");  
		List<String> list = jedis.lrange("sample:comment", 0, 100);  
		list.forEach(System.out::println);  
		  
		//设置500秒过期  
		jedis.expire("sample:comment", 500);  
		  
		//从左侧移除数据  
		jedis.lpop("sample:comment");  
	}  
	  
	@Test  
	void testSet() {  
		//创建set并插入数据  
		jedis.sadd("sample:rank", "6", "7", "8");  
		  
		//设置500秒过期  
		jedis.expire("sample:rank", 500);  
		  
		//移除某个元素  
		jedis.srem("sample:rank", "6");  
		  
		//获取所有元素  
		Set<String> set = jedis.smembers("sample:rank");  
		System.out.println("数据:" + set.toString());  
	}  
	  
	@Test  
	void testSortedSet() {  
		jedis.zadd("sample:goldRank", 100, "张三");  
		HashMap<String, Double> map = new HashMap<>();  
		map.put("李四", 200D);  
		map.put("王五", 150D);  
		  
		//设置500秒过期  
		jedis.expire("sample:goldRank", 500);  
		jedis.zrem("sample:goldRank", "王五");  
		  
		//获取指定排名范围内的元素及score  
		List<Tuple> list = jedis.zrangeWithScores("sample:goldRank", 1, 10);  
		list.forEach(System.out::println);  
	}  
	  
	@AfterEach  
	void tearDown() {  
		//释放资源  
		if (jedis != null) {  
		jedis.close();  
		}  
	}  
}
五、Redis的Java客户端-lettuce(Spring Data Redis包含该客户端) 
lettuce是基于netty实现的,支持同步、异步和响应式编程方式,并且是线程安全的。
支持Redis的哨兵模式、集群模式和管道模式。
六、Redis的Java客户端-Redisson
Redisson是一个基于Redis实现的分布式、可伸缩的Java数据结构集合。
包含了诸如Map、Queue、Lock、semaphore、AtomicLong等强大功能。
七、SpringDataRedis
SpringData是Spring中数据操作的模块,包含对各种数据库的集成,
其中对Redis的集成模块就叫做SpringDataRedis,
官网地址:https://spring.io/projects/spring-data-redis

提供了对不同Redis客户端的整合(Lettuce和Jedis)
提供了RedisTemplate统一API来操作Redis
支持Redis的发布订阅模型
支持Redis哨兵和Redis集群
支持基于Lettuce的响应式编程
支持基于JDK、JSON、字符串、Spring对象的数据序列化及反序列化
支持基于Redis的JDK Collection实现
1、gradle引入依赖
//spring-boot-starter-data-redis依赖  
implementation 'org.springframework.boot:spring-boot-starter-data-redis'  
  
//连接池依赖,jedis和spring-boot-starter-data-redis都需要  
implementation 'org.apache.commons:commons-pool2:2.10.0'
2、配置application.yml
server:  
	port: 8050  
  
spring:  
	redis:  
		host: localhost  
		port: 6379  
		password:  
		lettuce: # jedis:  
			pool:  
				max-active: 8 # 最大连接  
				max-idle: 8 # 最大空闲连接  
				min-idle: 0 # 最小空闲连接  
				max-wait: 100 # 连接等待时间  
		database: 1
3、方式一:使用RedisTemplate工具类,需要自定义RedisTemplate处理序列化
/**
* 自定义RedisTemplate,修改RedisTemplate的序列化器,避免key-value乱码,
* 但java对象json序列化会将类的class类型写入json结果,存入Redis,会带来额外的内存开销。
*/
@Configuration  
public class RedisConfig {  
	@Bean  
	public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory connectionFactory){  
		//创建RedisTemplate对象  
		RedisTemplate<String,Object> redisTemplate=new RedisTemplate<>();  
		  
		//设置连接工厂  
		redisTemplate.setConnectionFactory(connectionFactory);  
		  
		//创建Json序列化工具  
		GenericJackson2JsonRedisSerializer jsonRedisSerializer=new GenericJackson2JsonRedisSerializer();  
		  
		//设置key的序列化  
		redisTemplate.setKeySerializer(RedisSerializer.string());  
		redisTemplate.setHashKeySerializer(RedisSerializer.string());  
		  
		//设置value的序列化  
		redisTemplate.setValueSerializer(jsonRedisSerializer);  
		redisTemplate.setHashValueSerializer(jsonRedisSerializer);  
		  
		//返回  
		return redisTemplate;  
	}  
}
// String类型存实体数据格式
{
	"@class": "com.fafa.jedis.User",
	"userId": 10001,
	"name": "张三三"
}

/**
* RedisTemplate测试示例
*/
@SpringBootTest  
public class RedisTemplateTests {  
	@Autowired  
	private RedisTemplate<String, Object> redisTemplate;  
	  
	@Test  
	void testString() {  
		//插入一条String类型数据  
		ValueOperations valueOperations = redisTemplate.opsForValue();  
		valueOperations.set("name", "李四");  
		  
		//存入java对象,会将类的class类型写入json  
		User user = new User(10001, "张三三");  
		valueOperations.set("user", user);  
		  
		//设置500秒过期  
		valueOperations.getOperations().expire("name", 500, TimeUnit.SECONDS);  
		  
		//读取一条String类型数据  
		Object name = valueOperations.get("name");  
		System.out.println("数据name=" + name);  
	}  
	  
	@Test  
	void testHash() {  
		//插入一条Hash类型数据  
		HashOperations hashOperations = redisTemplate.opsForHash();  
		hashOperations.put("sample:hs:score", "张三", "100");  
		  
		//追加键值对到hash  
		HashMap<String, String> map = new HashMap<>();  
		map.put("李四", "200");  
		map.put("王五", "150");  
		hashOperations.putAll("sample:hs:score", map);  
		  
		//设置500秒过期  
		hashOperations.getOperations().expire("sample:hs:score", 500, TimeUnit.SECONDS);  
		  
		//获取hash所有键值对  
		Map<String, String> m = hashOperations.entries("sample:hs:score");  
		System.out.println("数据:" + m.toString());  
	}  
	  
	@Test  
	void testList() {  
		//创建list并插入数据  
		ListOperations listOperations = redisTemplate.opsForList();  
		listOperations.leftPushAll("sample:comment", "a", "b");  
		listOperations.rightPushAll("sample:comment", "c", "d");  
		List<String> list = listOperations.range("sample:comment", 0, 100);  
		list.forEach(System.out::println);  
		  
		//设置500秒过期  
		listOperations.getOperations().expire("sample:comment", 500, TimeUnit.SECONDS);  
		  
		//从左侧移除数据  
		listOperations.leftPop("sample:comment");  
	}  
	  
	@Test  
	void testSet() {  
		//创建set并插入数据  
		SetOperations setOperations = redisTemplate.opsForSet();  
		setOperations.add("sample:rank", "6", "7", "8");  
		  
		//设置500秒过期  
		setOperations.getOperations().expire("sample:rank", 500, TimeUnit.SECONDS);  
		  
		//移除某个元素  
		setOperations.remove("sample:rank", "6");  
		  
		//获取所有元素  
		Set<String> set = setOperations.members("sample:rank");  
		System.out.println("数据:" + set.toString());  
	}  
	  
	@Test  
	void testSortedSet() {  
		ZSetOperations sortedSetOption = redisTemplate.opsForZSet();  
		sortedSetOption.add("sample:goldRank", "张三", 100);  
		HashMap<String, Double> map = new HashMap<>();  
		map.put("李四", 200D);  
		map.put("王五", 150D);  
		  
		//设置500秒过期  
		sortedSetOption.getOperations().expire("sample:goldRank", 500, TimeUnit.SECONDS);  
		sortedSetOption.remove("sample:goldRank", "王五");  
		  
		//获取指定排名范围内的元素  
		Set list = sortedSetOption.range("sample:goldRank", 0, 10);  
		list.forEach(System.out::println);  
	}  
}
4、方式二:StringRedisTemplate类,存储java对象时,需手动完成对象的序列化和反序列化
@SpringBootTest  
public class StringRedisTemplateTests {  
	@Autowired  
	private StringRedisTemplate stringRedisTemplate;  
	  
	//JSON工具  
	private static final ObjectMapper mapper = new ObjectMapper();  
	  
	@Test  
	void testString() throws JsonProcessingException {  
		//插入一条String类型数据  
		ValueOperations valueOperations = stringRedisTemplate.opsForValue();  
		valueOperations.set("name", "李四");  
		  
		//读取一条String类型数据  
		Object name = valueOperations.get("name");  
		System.out.println("数据name=" + name);  
		  
		//创建对象  
		User user = new User(10001, "张三三");  
		  
		//jackson手动序列化  
		String json = mapper.writeValueAsString(user);  
		//写入数据到redis  
		valueOperations.set("user", json);  
		  
		//读取数据  
		String val = (String) valueOperations.get("user");  
		//jackson反序列化  
		User user1 = mapper.readValue(val, User.class);  
		System.out.println("user1=" + user1);  
		  
		//设置500秒过期  
		valueOperations.getOperations().expire("name", 500, TimeUnit.SECONDS);  
	}  
	  
	@Test  
	void testHash() {  
		//插入一条Hash类型数据  
		HashOperations hashOperations = stringRedisTemplate.opsForHash();  
		hashOperations.put("sample:hs:score", "张三", "100");  
		  
		//追加键值对到hash  
		HashMap<String, String> map = new HashMap<>();  
		map.put("李四", "200");  
		map.put("王五", "150");  
		hashOperations.putAll("sample:hs:score", map);  
		  
		//设置500秒过期  
		hashOperations.getOperations().expire("sample:hs:score", 500, TimeUnit.SECONDS);  
		  
		//获取hash所有键值对  
		Map<String, String> m = hashOperations.entries("sample:hs:score");  
		System.out.println("数据:" + m.toString());  
	}  
	  
	@Test  
	void testList() {  
		//创建list并插入数据  
		ListOperations listOperations = stringRedisTemplate.opsForList();  
		listOperations.leftPushAll("sample:comment", "a", "b");  
		listOperations.rightPushAll("sample:comment", "c", "d");  
		List<String> list = listOperations.range("sample:comment", 0, 100);  
		list.forEach(System.out::println);  
		  
		//设置500秒过期  
		listOperations.getOperations().expire("sample:comment", 500, TimeUnit.SECONDS);  
		  
		//从左侧移除数据  
		listOperations.leftPop("sample:comment");  
	}  
	  
	@Test  
	void testSet() {  
		//创建set并插入数据  
		SetOperations setOperations = stringRedisTemplate.opsForSet();  
		setOperations.add("sample:rank", "6", "7", "8");  
		  
		//设置500秒过期  
		setOperations.getOperations().expire("sample:rank", 500, TimeUnit.SECONDS);  
		  
		//移除某个元素  
		setOperations.remove("sample:rank", "6");  
		  
		//获取所有元素  
		Set<String> set = setOperations.members("sample:rank");  
		System.out.println("数据:" + set.toString());  
	}  
	  
	@Test  
	void testSortedSet() {  
		ZSetOperations sortedSetOption = stringRedisTemplate.opsForZSet();  
		sortedSetOption.add("sample:goldRank", "张三", 100);  
		HashMap<String, Double> map = new HashMap<>();  
		map.put("李四", 200D);  
		map.put("王五", 150D);  
		  
		//设置500秒过期  
		sortedSetOption.getOperations().expire("sample:goldRank", 500, TimeUnit.SECONDS);  
		sortedSetOption.remove("sample:goldRank", "王五");  
		  
		//获取指定排名范围内的元素  
		Set list = sortedSetOption.range("sample:goldRank", 0, 10);  
		list.forEach(System.out::println);  
	}  
}


网站公告

今日签到

点亮在社区的每一天
去签到