redis系列:通过日志案例学习string命令

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
日志服务 SLS,月写入数据量 50GB 1个月
简介:

前言

该文章将通过一个小demo将讲述Redis中的string类型命令。demo将以springboot为后台框架快速开发,iview前端框架进行简单的页面设计,为了方便就不使用DB存储数据了,直接采用Redis作为存储。

文中不会讲述springboot用法及项目搭建部分。直接根据功能方面进行讲述,穿插string命令操作说明。

如果需要详细了解该项目的其他部分,请点击下方项目Github地址

项目Github地址:https://github.com/rainbowda/learnWay/tree/master/learnRedis/case-string

案例

demo功能是记录日志,整个demo的大致页面如下

准备工作

首先定义一个key的前缀,已经存储自增id的key

private static final String MY_LOG_REDIS_KEY_PREFIX = "myLog:";
private static final String MY_LOG_REDIS_ID_KEY = "myLogID";

日志相关的key将会以myLog:1、myLog:2、myLog:3的形式存储

redis操作对象

private RedisTemplate redisTemplate;
//string 命令操作对象
private ValueOperations valueOperations;

新增

先来看看gif图吧

来看看后台的方法

@RequestMapping(value = "/addMyLog",method = RequestMethod.POST)
public boolean addMyLog(@RequestBody JSONObject myLog){
    //获取自增id
    Long myLogId = valueOperations.increment(MY_LOG_REDIS_ID_KEY, 1);

    String date = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

    myLog.put("id",myLogId);
    myLog.put("createDate", date);
    myLog.put("updateDate", date);
    //将数据写到redis中
    valueOperations.set(MY_LOG_REDIS_KEY_PREFIX+myLogId, myLog.toString());

    return true;
}

从上面代码可以看出有两个操作redis的地方

valueOperations.increment(MY_LOG_REDIS_ID_KEY, 1);

valueOperations.set(MY_LOG_REDIS_KEY_PREFIX+myLogId, myLog.toString());

命令介绍

valueOperations.increment其实就相当于Redis中的INCR、INCRBY、INCRBYFLOAT、DECR、DECRBY

INCR

INCR key

对存储在指定key的数值执行原子的加1操作。没有对应的key则设置为0,再相加

INCRBY

INCRBY key increment

其实和INCR类似,不同的是这个命令可以指定具体加多少

INCRBYFLOAT

INCRBYFLOAT key increment

也是类似的,不同的是加的数值是浮点数

incrbyfloat incrByFloatKey 5.11
incrbyfloat incrByFloatKey 5.22

执行结果如下

下面是java代码

@Test
public void incrByFloat() {
    System.out.println(jedis.incrByFloat("incrByFloatKey", 5.11));

    System.out.println(redisTemplate.opsForValue().increment("incrByFloatKey", 5.22));
}

与INCR相反的命令有DECR和DECRBY,这里就不做介绍了。


valueOperations.set就是对应Redis的SET命令了,相关联的还有SETEX、SETNX和PSETEX。需要注意的是set在Redis版本2.6.12 提供了EXPXNXXX参数用于取代SETEX、SETNX和PSETEX,后续版本可能会移除SETEX、SETNX和PSETEX命令。下面是官网的原话

Since the SET command options can replace SETNXSETEXPSETEX, it is possible that in future versions of Redis these three commands will be deprecated and finally removed.

SET

SET key value [expiration EX seconds|PX milliseconds] [NX|XX]

设置键key对应value
参数选项

EX seconds – 设置键key的过期时间,单位时秒

PX milliseconds – 设置键key的过期时间,单位时毫秒
NX – 只有键key不存在的时候才会设置key的值
XX – 只有键key存在的时候才会设置key的值

SETRANGE

SETRANGE key offset value

替换从指定长度开始的字符

set setRangeKey "Hello World"
setrange setRangeKey 6 "Redis"
get setRangeKey

执行结果如下

下面是java代码

@Test
public void setRange() {
    jedis.set("setRangeKey", "Hello World");

    jedis.setrange("setRangeKey", 6 , "Redis");
    System.out.println(jedis.get("setRangeKey"));

    //spring
    redisTemplate.opsForValue().set("setRangeKey", "learyRedis", 6);
    System.out.println(redisTemplate.opsForValue().get("setRangeKey"));
}
MSET

MSET key value [key value ...]

同时设置多个key、value

 MSETNX

MSETNX key value [key value ...]

同时设置多个key、value,key存在则忽略

查询

接着写个查询方法,将新增的内容查询出来

@RequestMapping(value = "/getMyLog",method = RequestMethod.GET)
public List getMyLog(){
    //获取mylog的keys
    Set myLogKeys = redisTemplate.keys("myLog:*");
    return  valueOperations.multiGet(myLogKeys);
}

方法中的两行都涉及到了Redis操作,先是通过keys命令获取myLog:*相关的key集合,然后通过multiGet方法(也就是mget命令)获取记录。

命令介绍
KEYS

KEYS pattern

查找所有符合给定模式pattern(正则表达式)的 key

GET

GET key

获取key对应的value

set getKey getValue
get getKey

执行结果如下

GETRANGE

GETRANGE key start end

获取start到end之间的字符

set getRangeKey "Hello learyRedis"
getrange getRangeKey 6 -1
getrange getRangeKey 0 -12

执行结果如下

GETSET

GETSET key value

设置key对应的新value且返回原来key对应的value

getset getSetKey newValue
set getSetKey value
getset getSetKey newValue
get getSetKey

执行结果如下

MGET

MGET key [key ...]

返回所有指定的key的value

mset mGetKey1 mGetValue1 mGetKey2 mGetValue2 mGetKey3 mGetValue3
mget mGetKey1 mGetKey2 mGetKey3 mGetKey4

执行结果如下

更新

来看看代码

@RequestMapping(value = "/updateMyLog",method = RequestMethod.POST)
public boolean updateMyLog(@RequestBody JSONObject myLog){
    String myLogId = myLog.getString("id");
    myLog.put("updateDate", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

    valueOperations.set(MY_LOG_REDIS_KEY_PREFIX+myLogId, myLog.toString());
    return true;
}

这里的set在新增方法里面讲述过,那么来看看APPEND、STRLEN命令吧

命令介绍
APPEND

APPEND key value

在value的尾部追加新值

redis客户端执行的命令如下

append appendKey append
append appendKey Value
get appendKey

执行结果如下

STRLEN

STRLEN key

返回value的长度

删除

代码如下

@RequestMapping(value = "/delMyLog/{id}", method = RequestMethod.DELETE)
public boolean delMyLog(@PathVariable  String id){
    return redisTemplate.delete(MY_LOG_REDIS_KEY_PREFIX + id);
}

可以看到代码中只用了delete方法,对应着Redis的DEL命令(属于基本命令)

命令介绍
DEL

DEL key [key ...]

删除key

BIT相关命令

bit命令有SETBIT、GETBIT、BITCOUNT、BITFIELD、BITOP、BITPOS这些。
命令这里就不做介绍了,直接讲述bit相关的案例。

Pattern: real time metrics using bitmaps
BITOP is a good complement to the pattern documented in the BITCOUNT command documentation. Different bitmaps can be combined in order to obtain a target bitmap where the population counting operation is performed.

See the article called "Fast easy realtime metrics using Redis bitmaps" for a interesting use cases.

案例地址Fast easy realtime metrics using Redis bitmaps
网上译文也有许多,有需要的百度或者google即可

这里大概讲述下使用位图法统计日登入用户数、周连续登入用户数和月连续登入用户数

位图法就是bitmap的缩写,所谓bitmap,就是用每一位来存放某种状态,适用于大规模数据,但数据状态又不是很多的情况。通常是用来判断某个数据存不存在的。 ------来自百度百科

就好像java中int有4个字节,也就是32位。当32位全为1时,也就是int的最大值。

位只能被设置位0或者1,也就是二进制。

java中可以用BitSet来操作位的相关操作

场景

有一万个用户,id从1到10000,根据当前是否上线,来设置在第id位上是否为1或者0。通过每天的记录来统计用户连续上线的情况。

分析

一号有id为5、3、1的上线了,二号有id为5、4、3的上线了,三号有id为3、2、1的上线了。存储的数据如下

序号:5 4 3 2 1 0
一号:1 0 1 0 1 0
二号:1 1 1 0 0 0
三号:0 0 1 1 1 0

那么我们只有将三天的数据进行与操作就可以知道,三天连续上线的有哪些了,与操作的结果如下

序号:5 4 3 2 1 0
结果:0 0 1 0 0 0

很明显是id为3的用户连续登入3天。

代码

先定义一些常量

//存储的key前缀
private static final String ONLINE_KEY_PREFIX = "online:";
//天数
private static final int DAY_NUM = 30;
//用户数量
private static final int PEOPLE_NUM = 10000;

然后模拟一个月的数据


public void createData() {
    //用来保证线程执行完在进行后面的操作
    CountDownLatch countDownLatch = new CountDownLatch(DAY_NUM);

    int poolSize = Runtime.getRuntime().availableProcessors() * 2;
    ThreadPoolExecutor executor = new ThreadPoolExecutor(poolSize, poolSize, 60, TimeUnit.SECONDS, new ArrayBlockingQueue(DAY_NUM-poolSize));
    //DAY_NUM天
    for (int i = 1; i <= DAY_NUM; i++) {
        int finalI = i;
        executor.execute(() -> {
            //假设有PEOPLE_NUM个用户
            for (int j = 1; j <= PEOPLE_NUM; j++) {
                redisTemplate.opsForValue().setBit(ONLINE_KEY_PREFIX + finalI, j, Math.random() > 0.1);
            }
            countDownLatch.countDown();
        });
    }

    //等待线程全部执行完成
    try {
        countDownLatch.await();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

最后是统计

public void calActive(int day) {
    if (day < 0 || day > DAY_NUM){
        throw new IllegalArgumentException("传入的天数不能小于0或者大于30天!");
    }

    long calStart = System.currentTimeMillis();
    BitSet active = new BitSet();
    active.set(0, PEOPLE_NUM);
    for (int i = 1; i <= day; i++) {
        BitSet bitSet = BitSet.valueOf(jedis.get((ONLINE_KEY_PREFIX + i).getBytes()));
        active.and(bitSet);
    }
    long calEnd = System.currentTimeMillis();
    System.out.println(day + "天的上线用户" + active.cardinality() + ",花费时长:" + (calEnd - calStart));
}

测试方法

@Test
public void daliyActive() {
    /**
     *模拟数据
     */
    createData();

    /**
     * 开始统计
     */
    //1
    calActive(1);

    //7
    calActive(7);

    //15
    calActive(15);

    //30
    calActive(30);
}

测试结果

1天的上线用户9015,花费时长:0
7天的上线用户4817,花费时长:0
15天的上线用户2115,花费时长:0
30天的上线用户431,花费时长:15

有需要看相关代码的请点击GITHUB地址

其他

关于其他相关的命令可以查看下方地址

string全命令

Redis基本命令

命令比较多,但是还是建议学习的人最好每个命令都去敲下,加深印象。
下面诗句送给每一个阅读的人。

纸上得来终觉浅,绝知此事要躬行。————出自《冬夜读书示子聿》

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
1月前
|
NoSQL Java Redis
redis的基本命令,并用netty操作redis(不使用springboot或者spring框架)就单纯的用netty搞。
这篇文章介绍了Redis的基本命令,并展示了如何使用Netty框架直接与Redis服务器进行通信,包括设置Netty客户端、编写处理程序以及初始化Channel的完整示例代码。
38 1
redis的基本命令,并用netty操作redis(不使用springboot或者spring框架)就单纯的用netty搞。
|
19天前
|
NoSQL Redis
Redis 字符串(String)
10月更文挑战第16天
31 4
|
3天前
|
存储 NoSQL Java
Redis命令:列表模糊删除详解
通过本文的介绍,我们详细探讨了如何在Redis中实现列表的模糊删除。虽然Redis没有直接提供模糊删除命令,但可以通过组合使用 `LRANGE`和 `LREM`命令,并在客户端代码中进行模糊匹配,来实现这一功能。希望本文能帮助你在实际应用中更有效地操作Redis列表。
8 0
|
29天前
|
缓存 NoSQL 测试技术
Redis如何解决频繁的命令往返造成的性能瓶颈!
Redis如何解决频繁的命令往返造成的性能瓶颈!
|
29天前
|
存储 数据可视化 安全
一个简单案例,带你看懂GC日志!
一个简单案例,带你看懂GC日志!
一个简单案例,带你看懂GC日志!
|
1月前
|
存储 Prometheus NoSQL
大数据-44 Redis 慢查询日志 监视器 慢查询测试学习
大数据-44 Redis 慢查询日志 监视器 慢查询测试学习
22 3
|
1月前
|
存储 分布式计算 NoSQL
大数据-40 Redis 类型集合 string list set sorted hash 指令列表 执行结果 附截图
大数据-40 Redis 类型集合 string list set sorted hash 指令列表 执行结果 附截图
24 3
|
1月前
|
缓存 NoSQL Redis
Redis命令:列表模糊删除详解
Redis命令:列表模糊删除详解
39 3
|
1月前
|
NoSQL 关系型数据库 MySQL
Redis 事务特性、原理、具体命令操作全方位诠释 —— 零基础可学习
本文全面阐述了Redis事务的特性、原理、具体命令操作,指出Redis事务具有原子性但不保证一致性、持久性和隔离性,并解释了Redis事务的适用场景和WATCH命令的乐观锁机制。
171 0
Redis 事务特性、原理、具体命令操作全方位诠释 —— 零基础可学习
|
20天前
|
NoSQL Redis 数据安全/隐私保护
Redis 命令
10月更文挑战第15天
23 0