Redis —— Redis In Action —— Redis 实战—— 基础篇 —— Redis 的常见命令解析 以及 Redis 结合客户端的快速上手使用—— SpringData Redis

本篇文章简介

本篇文章是参阅 黑马程序员Redis入门到实战教程,全面透析redis底层原理 整理的二刷笔记 —— 备战 2022秋招 —— 继续加油努力!!!

📖 Redis 实战 —— 基础篇

📑 Redis 常见命令

🔖 Redis 数据结构介绍

在这里插入图片描述

官方命令地址:Commands | Redis

可以通过下列命令快速查看使用说明

127.0.0.1:6379> help
redis-cli 6.2.6
To get help about Redis commands type:
      "help @<group>" to get a list of commands in <group>
      "help <command>" for help on <command>
      "help <tab>" to get a list of possible help topics
      "quit" to exit

To set redis-cli preferences:
      ":set hints" enable online hints
      ":set nohints" disable online hints
Set your preferences in ~/.redisclirc
⭐ 通用命令

1️⃣ KEYS : 查看符合模板的所有 key——不建议在生产环境设备上使用

可以通过 help [command] 可以查看一个命令的具体用法,例如:

127.0.0.1:6379> help KEYS

  KEYS pattern
  summary: Find all keys matching the given pattern
  since: 1.0.0
  group: generic

Supported glob-style patterns:

  • h?llo matches hello, hallo and hxllo
  • h*llo matches hllo and heeeello
  • h[ae]llo matches hello and hallo, but not hillo
  • h[^e]llo matches hallo, hbllo, … but not hello
  • h[a-b]llo matches hallo and hbllo

Examples

redis:6379> MSET firstname Jack lastname Stuntman age 35
"OK"
redis:6379> KEYS *name*
1) "firstname"
2) "lastname"
redis:6379> KEYS a??
1) "age"
redis:6379> KEYS *
1) "firstname"
2) "age"
3) "lastname"
redis:6379> 

2️⃣ DEL :删除指定的KEY —— 也可以删除多个 KEY

help

127.0.0.1:6379> help DEL

  DEL key [key ...]
  summary: Delete a key
  since: 1.0.0
  group: generic

📚 Removes the specified keys. A key is ignored if it does not exist.

Example

redis:6379> SET key1 "Hello"
"OK"
redis:6379> SET key2 "World"
"OK"
redis:6379> DEL key1 key2 key3
(integer) 2
redis:6379> 

3️⃣ EXISTS:判断对应的 KEY 是否存在

help

127.0.0.1:6379> help EXISTS

  EXISTS key [key ...]
  summary: Determine if a key exists
  since: 1.0.0
  group: generic

📚 The user should be aware that if the same existing key is mentioned in the arguments multiple times, it will be counted multiple times. So if somekey exists, EXISTS somekey somekey will return 2.

Example

redis:6379> SET key1 "Hello"
"OK"
redis:6379> EXISTS key1
(integer) 1
redis:6379> EXISTS nosuchkey
(integer) 0
redis:6379> SET key2 "World"
"OK"
redis:6379> EXISTS key1 key2 nosuchkey
(integer) 2
redis:6379> 

4️⃣ EXPIRE:给一个 key 设置有效期,有效期到期时该 KEY 会被自动删除

EXPIRE KEY seconds [NX|XX|GT|LT]

help

127.0.0.1:6379> help EXPIRE

  EXPIRE key seconds
  summary: Set a key's time to live in seconds
  since: 1.0.0
  group: generic

The EXPIRE command supports a set of options:

  • NX – Set expiry only when the key has no expiry
  • XX – Set expiry only when the key has an existing expiry
  • GT – Set expiry only when the new expiry is greater than current one
  • LT – Set expiry only when the new expiry is less than current one

Example

redis:6379> SET mykey "Hello"
"OK"
redis:6379> EXPIRE mykey 10
(integer) 1
redis:6379> TTL mykey
(integer) 10
redis:6379> SET mykey "Hello World"
"OK"
redis:6379> TTL mykey
(integer) -1
redis:6379> EXPIRE mykey 10 XX
(integer) 0
redis:6379> TTL mykey
(integer) -1
redis:6379> EXPIRE mykey 10 NX
(integer) 1
redis:6379> TTL mykey
(integer) 10
redis:6379> 

5️⃣ TTL:查看一个 KEY 的剩余有效期

help

127.0.0.1:6379> help TTL

  TTL key
  summary: Get the time to live for a key
  since: 1.0.0
  group: generic

📚 Starting with Redis 2.8 the return value in case of error changed:

  • The command returns -2 if the key does not exist.
  • The command returns -1 if the key exists but has no associated expire.

Example

redis:6379> SET mykey "Hello"
"OK"
redis:6379> EXPIRE mykey 10
(integer) 1
redis:6379> TTL mykey
(integer) 10

⭐ String

在这里插入图片描述

常用命令


1️⃣ SET:添加或者修改已经存在的一个String类型的键值对


2️⃣ GET:根据 KEY 获取 String 类型的 value


3️⃣ MSET:批量添加多个 String 类型的键值对


4️⃣ MGET:根据多个 KEY 获取多个 String 类型的 value


5️⃣ INCR:让一个整型的 KEY 自增 1


6️⃣ INCRBY:让一个整型的 KEY 自增并指定步长


7️⃣ INCRBYFLOAT:让一个浮点类型的数字自增并指定步长


8️⃣ SETNX:添加一个 String 类型的键值对,前提是这个 KEY 不存在,否则不执行


9️⃣ SETEX:添加一个 String类型的键值对,并且指定有效期


非常用命令

1️⃣ SUBSTR:根据 KEY 获取 String 指定范围的 subString


2️⃣ STRLEN:根据 KEY 获取 String 字符串的长度


3️⃣ GETRANGE:用于获取存储在指定 key 中的子字符串。


4️⃣ GETSET:返回之前的值,在设置新的值。


5️⃣ GETDEL:返回之前的值,然后删除对应的 KEY - VALUE


❓ Redis 没有类似MySQL 中的 Table 的概念,我们该如何区分不同类型的key呢?

举个🌰

  • 例如,需要存储用户、商品信息到 redis,有一个用户 id 是1 ,有一个商品 id 也是 1

在这里插入图片描述

⭐ Hash

在这里插入图片描述

常用命令

1️⃣ HSET:添加 或者 修改 hash 类型 key 的 field 的值。

HSET key field value [field value ...]


2️⃣ HGET :获取一个 hash 类型 key 的 field 的值。


3️⃣ HMSET:批量添加多个 hash 类型 key 的 field 的值


4️⃣ HMGET:批量获取多个 hash 类型的 key 中的所有的 field 和 value


5️⃣ HGETALL:获取一个 hash 类型的 key 中的所有的 field和value


6️⃣ HKEYS:获取一个 hash 类型的 key 中的所有的 field


7️⃣ HVALS:获取一个 hash 类型的 key 中的所有的 value


8️⃣ HINCRBY:让一个 hash 类型 key 的字段值 自增并指定步长


9️⃣ HSETNX:添加一个 hash 类型的 key 的 field 值,前提是这个 field 不存在,否则不执行。


非常用命令

1️⃣ HDEL :删除指定 hash 类型的key 中的一个或者多个 field


2️⃣ HLEN:获取指定 hash 类型的 key 中的 field 个数


⭐ List

在这里插入图片描述

常见命令

1️⃣ LPUSH key element … :向列表的左侧插入一个或者多个元素。


2️⃣ LPOP key:移除并返回列表左侧的第一个元素,没有则返回null。


3️⃣ RPUSH key element … :向列表右侧插入一个或多个元素。


4️⃣ RPOP key :移除并返回列表右侧的第一个元素


5️⃣ LRANGE key start end:返回一段角标范围内的所有元素。


6️⃣ BLPOP 和 BRPOP:与LPOP 和 RPOP 类似,只不过在没有元素时等待指定时间,而不是直接返回 null。


非常用命令

1️⃣ RPOPLPUSH:移除源List中的最后一个元素,将其插入到目标List当中。

help

127.0.0.1:6379> help RPOPLPUSH

  RPOPLPUSH source destination
  summary: Remove the last element in a list, prepend it to another list and return it
  since: 1.2.0
  group: list

Example

redis:6379> RPUSH mylist "one"
(integer) 1
redis:6379> RPUSH mylist "two"
(integer) 2
redis:6379> RPUSH mylist "three"
(integer) 3
redis:6379> RPOPLPUSH mylist myotherlist
"three"
redis:6379> LRANGE mylist 0 -1
1) "one"
2) "two"
redis:6379> LRANGE myotherlist 0 -1
1) "three"

课后问题

❓ 如何利用 List 结构模拟一个栈

❓ 如何利用 List 结构模拟一个队列

❓ 如何利用 List 结构模拟一个阻塞队列

⭐ Set

在这里插入图片描述

常用命令

1️⃣ SADD key member … : 向 set 中添加一个或者多个元素。


2️⃣ SREM key member …:移除 set 中的指定元素。


3️⃣ SCARD key : 返回 set 中元素的个数。


4️⃣ SISMEMBER key member :判断一个元素是否存在于 set 中


5️⃣ SMEMBERS : 显示 set 集合中的所有元素。


常用操作命令

1️⃣ SDIFF key [key] : key 所对应集合元素之差


2️⃣ SDIFFSTORE destination key [key] :和上述命令作用是一样的,不过会创建一个新的键为key的 set 用于存储结果集,如果这个结果集存在则会被覆盖。


3️⃣ SINTER key [key]:用于筛选 交集 集合操作


4️⃣ SINTERSTORE destination key [key] :和上述命令作用是一样的,不过会创建一个新的键为key的 set 用于存储结果集,如果这个结果集存在则会被覆盖。


5️⃣ SSCAN key cursor [MATCH pattern] [COUNT count]:迭代优化返回 set 数据集


❓ SET 命令的练习

在这里插入图片描述

将下列数据用 Redis 的 set 集合来存储

127.0.0.1:6379> SADD user:zhangsan:friends lisi wangwu zhaoliu
(integer) 3
127.0.0.1:6379> SMEMBERS user:zhangsan:friends
1) "zhaoliu"
2) "wangwu"
3) "lisi"
127.0.0.1:6379> SADD user:lisi:friends wangwu mazi ergou
(integer) 3
127.0.0.1:6379> SMEMBERS user:lisi:friends
1) "mazi"
2) "wangwu"
3) "ergou"

计算 张三的好友有几人

127.0.0.1:6379> SINTER user:zhangsan:friends user:lisi:friends
1) "wangwu"

计算张三和李四有哪些共同好友

127.0.0.1:6379> SINTER user:zhangsan:friends user:lisi:friends
1) "wangwu"

查询哪些人是张三的好友 却不是 李四的好友

127.0.0.1:6379> SDIFF user:zhangsan:friends user:lisi:friends
1) "zhaoliu"
2) "lisi"

查询张三和李四的好友总共有哪些人

127.0.0.1:6379> SUNION user:zhangsan:friends user:lisi:friends
1) "lisi"
2) "mazi"
3) "ergou"
4) "zhaoliu"
5) "wangwu"

判断李四是否是张三的好友

127.0.0.1:6379> SISMEMBER user:zhangsan:friends lisi
(integer) 1

判断张三是不是李四的好友

127.0.0.1:6379> SISMEMBER user:lisi:friends zhangsan
(integer) 0

将 李四 从张三的好友列表中移除

127.0.0.1:6379> SREM user:zhangsan:friends lisi
(integer) 1

⭐ SortedSet

在这里插入图片描述

常见命令

1️⃣ ZADD key score member:添加一个或多个元素到 sorted set


2️⃣ ZREM key member:删除 sorted set 中的一个指定元素


3️⃣ ZSCORE key member :获取sorted set 中的指定元素的 score 值


4️⃣ ZRANK key member :获取 sorted set 中指定元素的排名。


5️⃣ ZCARD key :获取 sorted set 中的元素个数


6️⃣ ZCOUNT key min max:统计 score 值在给定范围内的元素个数。


7️⃣ ZINCRBY key increment member:让 sorted set 中的指定元素自增,步长为指定的 increment 值。


8️⃣ ZRANGE key min max:按照 score 排序后,获取指定排名范围内的元素


9️⃣ ZRANGEBYSCORE key min max:按照 score排序后,获取指定 score 范围内的元素。


🔢 ZDIFF 、ZINTER、ZUNION:求差集、交集、并集。


📚 注意点:

所有排名默认都是升序,如果要降序则在命令的Z 后面添加REV (reverse)即可

❓ SortedSet 命令的练习

在这里插入图片描述

将班级的下列学生得分存入 Redis 的 SortedSet 中:

127.0.0.1:6379> ZADD student 85 Jack 82 Rose 95 Tom 78 Jerry 92 Amy 76 Miles
(integer) 6
127.0.0.1:6379> ZSCAN student 0
1) "0"
2)  1) "Miles"
    2) "76"
    3) "Jerry"
    4) "78"
    5) "Rose"
    6) "82"
    7) "Jack"
    8) "85"
    9) "Amy"
   10) "92"
   11) "Tom"
   12) "95"

删除 Tom 同学

127.0.0.1:6379> zrem student Tom
(integer) 1

获取 Amy 同学的分数

127.0.0.1:6379> ZSCORE student Amy
"92"

获取 Rose 同学的排名

127.0.0.1:6379> ZREVRANK student Rose
(integer) 2

查询 80 分以下的同学有几个学生

127.0.0.1:6379> ZCOUNT student 0 80
(integer) 2

给 Amy 同学 加 2 分

127.0.0.1:6379> ZINCRBY student 2 Amy
"94"

查出成绩前3名的同学

127.0.0.1:6379> ZREVRANGE student 0 2
1) "Amy"
2) "Jack"
3) "Rose"

查询成绩 80 分以下的所有同学

127.0.0.1:6379> ZRANGEBYSCORE student 0 80
1) "Miles"
2) "Jerry"

📑 Redis 的 Java 客户端

Clients | Redis

在这里插入图片描述

🔖 Jedis

Jedis

以 Redis 命令作为方法名称,学习成本低,简单实用。但是 Jedis 实例是线程不安全的,多线程环境需要基于连接池来使用。

redis/jedis: Redis Java client designed for performance and ease of use. (github.com)

步骤一:引入相关的依赖

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>3.7.0</version>
</dependency>

步骤二:建立连接进行测试

/***
 * @author: Alascanfu
 * @date : Created in 2022/7/3 20:51
 * @description: RedisConnection
 * @modified By: Alascanfu
 **/
public class TestConnection {
    private final static String REDIS_HOST = "192.168.56.103";
    private final static Integer REDIS_PORT = 6379 ;
    
    public static Jedis getJedisConnection(){
        return new Jedis(REDIS_HOST,REDIS_PORT);
    }
    
    public static boolean closeJedisConnection(Jedis jedisConnection){
        if (jedisConnection != null){
            jedisConnection.close();
            return true ;
        }
        throw new RuntimeException("JedisConnection 已经关闭 请勿二次关闭!");
    }
    
    public static void main(String[] args) {
        // 创建 Redis 连接
        Jedis jedis = new Jedis(REDIS_HOST, REDIS_PORT);
        // 选择 Redis 的库
        jedis.select(0);
        // 测试 Redis 连接
        String ping = jedis.ping();
        System.out.println(ping);
    }
}

测试String

@Test
public void testString(){
    Jedis jedisConnection = getJedisConnection();
    
    String result = jedisConnection.set("name" , "Alascanfu");

    System.out.println("result => " + result);
    
    String name = jedisConnection.get("name");

    System.out.println("name => " + name);

    System.out.println(jedisConnection.del("name") == 0 ? "No" : "Yes");

    closeJedisConnection(jedisConnection);
}

测试 hash

@Test
public void testHash(){
    Jedis jedisConnection = getJedisConnection();

    jedisConnection.hset("www.alascanfu.com:user","name","Alascanfu");
    jedisConnection.hset("www.alascanfu.com:user","age","21");
    jedisConnection.hset("www.alascanfu.com:user","sex","Man");

    Map<String, String> map = jedisConnection.hgetAll("www.alascanfu.com:user");
    System.out.println(map);

    System.out.println(jedisConnection.del("www.alascanfu.com:user") == 0 ? "No" : "Yes");
    
    closeJedisConnection(jedisConnection);
}
⭐ Jedis 线程池

Jedis 本身是线程不安全的,并且频繁的创建和销毁连接会有性能损耗,因此我们推荐大家使用 Jedis 连接池代替 Jedis 的连接方式

JedisConnectionFactory

/***
 * @author: Alascanfu
 * @date : Created in 2022/7/3 21:45
 * @description: Jedis Connection Factory
 * @modified By: Alascanfu
 **/
public class JedisConnectionFactory {
    
    private static final String REDIS_HOST = "192.168.56.103";

    private static final Integer REDIS_PORT = 6379 ;
    
    private static final JedisPool jedisPool;
    
    static {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        // 设置最大连接数
        jedisPoolConfig.setMaxTotal(8);
        
        // 设置最大空闲连接数
        jedisPoolConfig.setMaxIdle(8);
    
        // 设置最小空闲连接数
        jedisPoolConfig.setMinIdle(0);
        
        // 设置最长等待时间
        jedisPoolConfig.setMaxWaitMillis(200);
        
        // 创建 jedis 连接池
        jedisPool = new JedisPool(jedisPoolConfig,REDIS_HOST,REDIS_PORT,1000);
        
    }
    
    // 通过 Jedis 线程池 获取 Jedis 连接
    private static Jedis getJedis(){
        return jedisPool.getResource();
    }
}

🔖 lettuce

Lettuce

Lettuce 是基于 Netty 实现的,支持同步、异步和响应编程方式,并且是线程安全的。支持 Redis 的哨兵模式、集群模式和管道模式。

🔖 Redisson

Redisson 是 一个基于 Redis 实现的分布式、可伸缩的 Java 数据结构集合。包含了诸如 Map 、Queue 、Lock、Semaphore、AtomicLong 等强大功能。

📑 SpringData Redis

在这里插入图片描述

🔖 SpringData Redis 快速入门

SpringData Redis 中提供了 RedisTemplate 工具类,其中封装了各种对 Redis 的操作。并将不同类型的操作 API 封装到不同的类型当中

API返回值类型说明
redisTemplate.opsForValue()ValueOperations操作 String 类型数据
redisTemplate.opsForHash()HashOperations操作 Hash 类型数据
redisTemplate.opsForList()ListOperations操作 List 类型数据
redisTemplate.opsForSet()SetOperations操作 Set 类型数据
redisTemplate.opsForZSet()ZSetOperations操作 Sorted Set类型数据
redisTemplate通用的命令

步骤一:引入相关依赖,SpringBoot已经提供了对 SpringDataRedis 的支持了

<!-- 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>
<!-- 处理 Json 的依赖 -->
<dependency>
   <groupId>com.fasterxml.jackson.core</groupId>
   <artifactId>jackson-databind</artifactId>
   <version>2.13.3</version>
</dependency>

步骤二:配置文件

pom.xml

spring:
  redis:
    host: 192.168.56.103
    port: 6379
    lettuce:
      pool:
        max-idle: 8 # 最大空闲连接
        min-idle: 0 # 最小空闲连接
        max-active: 8 # 最大连接数
        max-wait: 200 # 连接最长等待时间

步骤三:测试

@SpringBootTest
class SpringdataRedisApplicationTests {
   @Autowired
   private RedisTemplate redisTemplate ;
   
   @Test
   public void testString(){
      // 写入一条 String 数据
      redisTemplate.opsForValue().set("www.alascanfu.com:user","Alascanfu");
      
      // 获取一条 String 数据
      String str = (String) redisTemplate.opsForValue().get("www.alascanfu.com:user");
      System.out.println(str);
      
      Boolean delete = redisTemplate.delete("www.alascanfu.com:user");
      System.out.println(delete);
   }
}

🔖 SpringDataRedis 的序列化方式

SpringDataRedis 的序列化方式

在这里插入图片描述

添加配置 RedisConfig

/***
 * @author: Alascanfu
 * @date : Created in 2022/7/3 22:43
 * @description: Redis Config
 * @modified By: Alascanfu
 **/
@Configuration
public class RedisConfig {
    
    @Bean
    public RedisTemplate<String , Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws Exception{
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        
        redisTemplate.setConnectionFactory(redisConnectionFactory);
    
        GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer
            = new GenericJackson2JsonRedisSerializer();
        // key 和 hashKey 采用 String 序列化
        redisTemplate.setKeySerializer(RedisSerializer.string());
        redisTemplate.setHashKeySerializer(RedisSerializer.string());
        // value 和 hashValue 采用 JSON 序列化
        redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);
        redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);
        return redisTemplate;
    }
}

测试

@Test
public void testStringObject(){
   redisTemplate.opsForValue().set("user:201901094106",new User(201901094106L,"Alascanfu",21));
   
   User user = (User) redisTemplate.opsForValue().get("user:201901094106");
   System.out.println(user);

}

📚 此时就不会出现乱码的错误啦

在这里插入图片描述

🔖 SpringDataRedis 序列化带来的一些缺点

在这里插入图片描述

  • 所以为了解决上述问题的话我们需要弃用自动的序列化以及反序列化,采用统一的String序列化器,要求只能存储String 类型的 key 和 value。当需要存储 Java 对象时,手动完成对象的序列化与反序列化。

小付的方法

@Test
public void testStringObject() throws JsonProcessingException {
   User alascanfu = new User(201901094106L, "Alascanfu", 21);
   
   String body = objectMapper.writeValueAsString(alascanfu);
   
   redisTemplate.opsForValue().set("user:201901094106",body);
   
   body = (String) redisTemplate.opsForValue().get("user:201901094106");
   
   User user = objectMapper.readValue(body, User.class);
   System.out.println(user);
}

老师的方法

在这里插入图片描述

🔖 封装好的 JsonUtil

/***
 * @author: Alascanfu
 * @date : Created in 2022/7/3 23:31
 * @description: JsonUtil 工具类用于 将后端数据以 Json 方式发送给所需方,
 * 以及将获取的Json 数据转换为 对应的类型
 * @modified By: Alascanfu
 **/
@Slf4j
@Component
public class JsonUtil {
    @Autowired
    private static ObjectMapper objectMapper ;
    
    public static String toJson(Object object){
        try {
            objectMapper.writeValueAsString(object);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null ;
    }
    
    public static Object FromJsonTo(String body , Class classType){
        try {
            return objectMapper.readValue(body,classType);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null ;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Alascanfu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值