该文章将经过一个小demo将讲述Redis中的string类型命令。demo将以springboot为后台框架快速开发,iview前端框架进行简单的页面设计,为了方便就不使用DB存储数据了,直接采用Redis做为存储。前端
文中不会讲述springboot用法及项目搭建部分。直接根据功能方面进行讲述,穿插string命令操做说明。java
若是须要详细了解该项目的其余部分,请点击下方项目Github地址git
项目Github地址:github.com/rainbowda/l…github
demo功能是记录日志,整个demo的大体页面以下正则表达式
首先定义一个key的前缀,已经存储自增id的keyredis
private static final String MY_LOG_REDIS_KEY_PREFIX = "myLog:";
private static final String MY_LOG_REDIS_ID_KEY = "myLogID";
复制代码
日志相关的key将会以myLog:一、myLog:二、myLog:3的形式存储spring
redis操做对象springboot
private RedisTemplate redisTemplate;
//string 命令操做对象
private ValueOperations valueOperations;
复制代码
先来看看gif图吧bash
来看看后台的方法前端框架
@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 key
对存储在指定key的数值执行原子的加1操做。没有对应的key则设置为0,再相加
INCRBY key increment
其实和INCR相似,不一样的是这个命令能够指定具体加多少
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 提供了EX
、PX
、NX
、XX
参数用于取代SETEX、SETNX和PSETEX,后续版本可能会移除SETEX、SETNX和PSETEX命令。下面是官网的原话
Since the SET command options can replace SETNX, SETEX, PSETEX, it is possible that in future versions of Redis these three commands will be deprecated and finally removed.
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 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 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 pattern
查找全部符合给定模式pattern(正则表达式)的 key
GET key
获取key对应的value
set getKey getValue
get getKey
复制代码
执行结果以下
GETRANGE key start end
获取start到end之间的字符
set getRangeKey "Hello learyRedis"
getrange getRangeKey 6 -1
getrange getRangeKey 0 -12
复制代码
执行结果以下
GETSET key value
设置key对应的新value且返回原来key对应的value
getset getSetKey newValue
set getSetKey value
getset getSetKey newValue
get getSetKey
复制代码
执行结果以下
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 key value
在value的尾部追加新值
redis客户端执行的命令以下
append appendKey append
append appendKey Value
get appendKey
复制代码
执行结果以下
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 key [key ...] 删除key
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为五、三、1的上线了,二号有id为五、四、3的上线了,三号有id为三、二、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地址
关于其余相关的命令能够查看下方地址
命令比较多,可是仍是建议学习的人最好每一个命令都去敲下,加深印象。 下面诗句送给每个阅读的人。
纸上得来终觉浅,绝知此事要躬行。————出自《冬夜读书示子聿》