Redis常用概念及操作

数据库 存储的位置 数据逻辑结构 MySQL、Oracle等数据库 硬盘 关系型数据 Redis 内存 key-value

  • 支持的数据结构多:string、hash、set、list、zset

五种数据结构

常用数据结构: stringhash

字符串常用操作

原子加减

单值缓存

对象缓存

计数器

Web集群session共享

分布式系统全局序列号

对象缓存

Set常用操作

Set运算操作

微信抽奖小程序

  1. 点击参与抽奖加入集合
    SADD key {userlD}
  2. 查看参与抽奖所有用户
    SMEMBERS key
  3. 抽取count名中奖者
    SRANDMEMBER key [count] / SPOP key [count]

微信微博点赞,收藏,标签

  1. 点赞
    SADD like:{消息ID} {用户ID}
  2. 取消点赞
    SREM like:{消息ID} {用户ID}
  3. 检查用户是否点过赞
    SISMEMBER like:{消息ID} {用户ID}
  4. 获取点赞的用户列表
    SMEMBERS like:{消息ID}
  5. 获取点赞用户数
    SCARD like:{消息ID}

ZSet常用操作

Zset集合操作

Zset集合操作实现排行榜

1)点击新闻
ZINCRBY hotNews:20190819 1 守护香港
2)展示当日排行前十
ZREVRANGE hotNews:20190819 0 9 WITHSCORES
3)七日搜索榜单计算
ZUNIONSTORE hotNews:20190813-20190819 7 hotNews:20190813 hotNews:20190814... hotNews:20190819
4)展示七日排行前十
ZREVRANGE hotNews:20190813-20190819 0 9 WITHSCORES

其它命令

  • 比较鸡肋,一般不会使用它,此处仅做了解
  • 没有原子性

redis事务四大指令: MULTI、EXEC、DISCARD、WATCH。这四个指令构成了redis事务处理的基础。

redis 127.0.0.1:6379> MULTI            # 标记事务开始
OK

redis 127.0.0.1:6379> INCR user_id     # 多条命令按顺序入队
QUEUED

redis 127.0.0.1:6379> INCR user_id
QUEUED

redis 127.0.0.1:6379> INCR user_id
QUEUED

redis 127.0.0.1:6379> PING
QUEUED

redis 127.0.0.1:6379> EXEC             # 执行
1) (integer) 1
2) (integer) 2
3) (integer) 3
4) PONG

有关redis事务,经常会遇到的是两类错误:

redis客户端执行一条命令分4个过程: 发送命令-〉命令排队-〉命令执行-〉返回结果

未使用pipeline执行N条命令:

使用了pipeline执行N条命令:

客户端可以一次性发送多个请求而不用等待服务器的响应,待所有命令都发送完后再一次性读取服务的响应,这样可以极大的降低多条命令执行的网络传输开销,管道执行多条命令的网络开销实际上只相当于一次命令执行的网络开销。需要注意到是用pipeline方式打包命令发送,redis必须在 处理完所有命令前先缓存起所有命令的处理结果。打包的命令越多,缓存消耗内存也越多。所以并不是打包的命令越多越好。

pipeline中发送的每个command都会被server立即执行,如果执行失败,将会在此后的响应中得到信息;也就是pipeline并不是表达”所有command都一起成功”的语义,管道中前面命令失败,后面命令不会有影响,继续执行。

使用pipeline组装的命令个数不能太多,不然数据量过大,增加客户端的等待时间,还可能造成网络阻塞,可以将大量命令的拆分多个小的pipeline命令完成。

Redis在2.6推出了脚本功能,允许开发者使用Lua语言编写脚本传到Redis中执行。使用脚本的好处如下:

官网文档上有这样一段话:

A Redis script is transactional by definition, so everything you can do with a Redis transaction, you can also do with a script, and usually the script will be both simpler and faster.

示例:

jedis.set("product_stock_10016", "15");  //初始化商品10016的库存
String script = " local count = redis.call('get', KEYS[1]) " +
                " local a = tonumber(count) " +
                " local b = tonumber(ARGV[1]) " +
                " if a >= b then " +
                "   redis.call('set', KEYS[1], a-b) " +
                "   return 1 " +
                " end " +
                " return 0 ";
Object obj = jedis.eval(script, Arrays.asList("product_stock_10016"), Arrays.asList("10"));
System.out.println(obj);

注意,不要在Lua脚本中出现死循环和耗时的运算,否则redis会阻塞,将不接受其他的命令, 所以使用时要注意不能出现死循环、耗时的运算。redis是单进程、单线程执行脚本。管道不会阻塞redis。

Spring使用Redis

  • RedisTemplateStringRedisTemplate
  • Redis数据库连接池:lettuce

    4.0.0

        org.springframework.boot
        spring-boot-starter-parent
        2.7.5

    cn.daheww.demo
    demo-redis
    0.0.1-SNAPSHOT
    demo-redis
    demo-redis

        1.8

            org.springframework.boot
            spring-boot-starter-json

            org.springframework.boot
            spring-boot-starter-data-redis

            org.springframework.boot
            spring-boot-starter-test
            test

            org.projectlombok
            lombok

                org.springframework.boot
                spring-boot-maven-plugin

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.json.JsonReadFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.text.SimpleDateFormat;
import java.util.TimeZone;

/**
 * @author daheww
 * @date 2022/10/27
 */
@Configuration
@SuppressWarnings("all")
public class RedisConfig {

    public final static String TIME_ZONE = "GMT+8";
    public final static String DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss";

    @Bean
    public RedisTemplate redisCacheTemplate(RedisConnectionFactory redisConnectionFactory) {
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = getJackson2JsonRedisSerializer();
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

        // 为了开发方便,一般都是
        RedisTemplate template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);

        // 设置键(key)的序列化采用StringRedisSerializer。
        template.setKeySerializer(stringRedisSerializer);
        // 设置值(value)的序列化采用jackson的序列化。
        template.setValueSerializer(jackson2JsonRedisSerializer);

        // 设置hash键(key)的序列化采用StringRedisSerializer。
        template.setHashKeySerializer(stringRedisSerializer);
        // 设置hash值(value)的序列化采用jackson的序列化。
        template.setHashValueSerializer(jackson2JsonRedisSerializer);

        return template;
    }

    private Jackson2JsonRedisSerializer getJackson2JsonRedisSerializer() {
        // JSON序列化的细节配置
        ObjectMapper om = new ObjectMapper();
        om.setTimeZone(TimeZone.getTimeZone(TIME_ZONE));
        om.configure(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature(), true);
        // 设置全局的日期转换的格式
        om.setDateFormat(new SimpleDateFormat(DATETIME_FORMAT));
        // 实体转json时,属性值为NULL不参加序列化
        om.setSerializationInclusion(JsonInclude.Include.NON_NULL);

        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        return jackson2JsonRedisSerializer;
    }

    @Bean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        // StringRedisTemplate和RedisTemplate:
        //   1.StringRedisTemplate继承RedisTemplate
        //   2.区别主要在于他们使用的序列化类:
        //     RedisTemplate默认使用的是JdkSerializationRedisSerializer(存入数据会将数据先序列化成字节数组然后在存入Redis数据库)
        //    StringRedisTemplate使用的是StringRedisSerializer
        // 使用时注意事项:
        //     当你的redis数据库里面本来存的是字符串数据或者你要存取的数据就是字符串类型数据的时候,那么你就使用StringRedisTemplate即可。
        //     但是如果你的数据是复杂的对象类型,而取出的时候又不想做任何的数据转换,直接从Redis里面取出一个对象,那么使用RedisTemplate是更好的选择。

        // 构建StringRedisTemplate
        StringRedisTemplate stringTemplate = new StringRedisTemplate();
        stringTemplate.setConnectionFactory(redisConnectionFactory);
        stringTemplate.afterPropertiesSet();
        return stringTemplate;
    }

}

Original: https://www.cnblogs.com/daheww/p/16833277.html
Author: daheww
Title: Redis常用概念及操作

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/714180/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球