本文共 11031 字,大约阅读时间需要 36 分钟。
目录
目录
hset(key, field, value)
将哈希表 hash 中域 field 的值设置为 value。
如果给定的哈希表并不存在, 那么一个新的哈希表将被创建并执行 HSET 操作。
如果域 field 已经存在于哈希表中, 那么它的旧值将被新值 value 覆盖。
当 HSET 命令在哈希表中新创建 field 域并成功为它设置值时, 命令返回 1 ; 如果域 field 已经存在于哈希表, 并且 HSET 命令成功使用新值覆盖了它的旧值, 那么命令返回 0 。
hget(key, field):返回名称为key的hash中field对应的value
hgetall(key):返回名称为key的hash中所有的键(field)及其对应的value
HGET 命令在默认情况下返回给定域的值。
如果给定域不存在于哈希表中, 又或者给定的哈希表并不存在, 那么命令返回 nil 。
----------------------------------------------------------------------------------------------------------------------
看了这个shell提示再结合概念理解起来就清楚很多了。
1、hset一条数据,并看懂其存储的数据结构。
2、这时候我们修改这个field中的value
这里的key就相当于tablename,如果域已经在hash表中,hset时会将旧值改为新值。
对于实际业务来说:
如果新增ope_id,定时器会定时刷新到redis的key = basicOpe中,
final List<MOpeD> basicOpeList = dao2.find(MOpeD.class, "FROM MOpeD where validFlg = 'Y'");
basicOpeList.forEach(ope -> {
pipelined.hset("basicOpe", String.valueOf(ope.getOpeKey()), JacksonUtil.toJSONStr(ope));
//可以看出key是basicOpe,field是ope_key,value是ope_id
basicOpeData.put(String.valueOf(ope.getOpeKey()), JacksonUtil.toJSONStr(ope));
});
我新增一笔被刷新到redis中
如下图:
可以看到下面就是一长串字符串就是 value。
实际业务是这样的,如果我在表中update了我新增的那笔valid_flg这个栏位。
等下一次定时器run完后,我再次查看这个key的这个field,竟然还存在。郁闷的我再次翻看 hset的定义:
如果域 field 已经存在于哈希表中, 那么它的旧值将被新值 value 覆盖。
也就是说,我update的是value中的一个字段,fileld并未改变。所以old value不会被new value覆盖的。(7/31)
通过上面的例子的实践确实是如此,通过翻看代码,在业务层获取basicOpe的时候并不是hget而是hgetALL。
再看下图:
hgetAll得到了两行数据,从这个也可以看出hget 和hgetall的区别到底在哪里?
hgetall返回的是所有的域和值,本例来说,
“1) “00666”” - >key
“2) “00625””-> value
在返回值里,紧跟每个域名(field name)之后是域的值(value),所以返回值的长度是哈希表大小的两倍。
最后再review代码时发现,hset bisicOpe的代码:
final List<MOpeD> basicOpeList = dao2.find(MOpeD.class, "FROM MOpeD where validFlg = 'Y'");
basicOpeList.forEach(ope -> {
pipelined.hset("basicOpe", String.valueOf(ope.getOpeKey()), JacksonUtil.toJSONStr(ope));
//可以看出key是basicOpe,field是ope_key,value是ope_id
basicOpeData.put(String.valueOf(ope.getOpeKey()), JacksonUtil.toJSONStr(ope));
});
从上面的代码可以看出,每次往basicOpe写值时的sql是塞valid_flg = 'Y'的。当在界面上删除这个ope时,db中将valid_flg赋值为N。这样basicOpe再也获取不在这条数据了,所以也不会有 “如果域 field 已经存在于哈希表中, 那么它的旧值将被新值 value 覆盖。”
为了解决这个问题,应该在实际的业务代码中加入,增量删除valid_flg = 'N’的数据:具体做法很简单,只需要找到valid_flg = ‘N’的field,然后hdel即可,如下:
public void loadOpeBasicData(Jedis jedis){ try { //3.Ope final ListbasicOpeList = dao2.find(MOpeD.class, "FROM ***"); List basicOpeListToFlush = basicOpeList.stream().filter(mMopeD -> mMopeD.getValidFlg().equals("Y")).collect(Collectors.toList());// to flush List basicOpeListToDel = basicOpeList.stream().filter(mMopeD -> mMopeD.getValidFlg().equals("N")).collect(Collectors.toList()); //to delete basicOpeListToFlush.forEach(ope -> { jedis.hset("basicOpe", String.valueOf(ope.getOpeKey()), JacksonUtil.toJSONStr(ope)); }); basicOpeListToDel.forEach(ope ->{ jedis.hdel("basicOpe",String.valueOf(ope.getOpeKey()));//删除哈希表 key 中的一个或多个指定域,不存在的域将被忽略. }); } catch (Exception e) { logger.error(LoggerUtil.stackTraceToString(e)); e.printStackTrace(); } }
此外到前辈的这片博文:。目前我们的项目中仍有hgetAll的语法,因为实际业务之需求。
目前Coids QPS,时而也有OPS飙升的情况,不过目前redis的内存还够用,至于后续,随着业务的其他需要增多redis的使用,我想hgetall也是需要改善的。
------------------------------------------------------update 2019年7月31日09:22:03-----------------------------------------------
在实际业务中,遇到baiscMachinespec 这个key中有脏数据导致alarm发不出。后来查看了原因:
用户在界面维护了一笔数据,比如新增了machineName = ASSM0399 aliaslinename = ‘SIBW03’。用户某天删除了machineName = ASSM0399的那一笔数据,然后新增了machineName = ASSM0398 aliaslinename = ‘SIBW03’的一笔,对于machinename维护角度来说这没有问题,可是对RTM业务来说这样维护是会产生一对多的问题。baiscMachinespec的 field 是machinename。value 是 “"{\"aliaslinename\":\"OLBX0648\",\"department\":\"\xe5\xae\x9e\xe8\xa3\x85\xe7\xa7\x91\",\"machinename\":\"AOPS0609\"}"”
形如这种的value.
如何选取合适的filed 是需要考虑的
-----------------------update 2019年7月19日13:40:21---------------------------------------
是set的一个升级版本,在set的基础上增加了一个顺序属性,这一属性在添加修改元素时可以指定,每次指定后zset会自动安装指定值重新调整顺序。可以理解为一张表,一列存value,一列存顺序。操作中的key理解为zset的名字。
Zset的最大元素数是2^32-1。
对于已经有序的zset,仍然可以使用SORT命令,通过指定ASC|DESC参数对其进行排序。
通过客户端help查看其用法
127.0.0.1:6380> help @sorted_set ZADD key [NX|XX] [CH] [INCR] score member [score member ...] summary: Add one or more members to a sorted set, or update its score if it already exists since: 1.2.0...............
ZADD key score member [[score member] [score member] ...]
127.0.0.1:6380> zadd testKey 1 var1(integer) 1127.0.0.1:6380> zadd testKey 2 var2(integer) 1127.0.0.1:6380> zadd testKey 3 var3(integer) 1127.0.0.1:6380> zrange testKey 0 -1 WITHSCORES1) "var1"2) "1"3) "var2"4) "2"5) "var3"6) "3"add 同一个score,会写入新的kv127.0.0.1:6380> zadd testKey 3 var3_1(integer) 1127.0.0.1:6380> zrange testKey 0 -1 withscores1) "var1"2) "1"3) "var2"4) "2"5) "var3"6) "3"7) "var3_1"8) "3"add旧的value到新的socre中?var3已经是有序集的成员,那么更新这个 var3 的score 值,并通过重新插入,来保证该 var3在正确的位置上。如下例子所示127.0.0.1:6380> zadd testKey 4 var3(integer) 0127.0.0.1:6380> zrange testKey 0 -1 withscores1) "var1"2) "1"3) "var2"4) "2"5) "var3_1"6) "3"7) "var3"8) "4"
有序集合可以干什么呢?
排行榜、有序时间以及评论+分页(评论是元素,score是分值,分页时给出score,按分页只需给传不同的score,动态分页也可以实现,在翻页时有新评论也不会有影响 ) 都可以采用这种集合来处理。
这个有序是如何实现的呢?
1、查看类型
127.0.0.1:6380> type testKey zset
2、查看底层数据结构
127.0.0.1:6380> OBJECT encoding testKey "skiplist"
skiplist的底层原理是什么呢?
当value的字节超过64字节时会存成skiplist,否则会直接存为ziplist。
127.0.0.1:6380> zadd k1 3.5 apple 7.2 orange 1.6 banana(integer) 3127.0.0.1:6380> OBJECT encoding k1"ziplist"
--------------------------------update 2019年12月6日10:30:51------------------------------------------------
Redis Zscan 命令用于迭代有序集合中的元素(包括元素成员和元素分值)
zscan history:A1300 0 match '*:*:*:*:*:**M' count 10000
127.0.0.1:19000> zrange LINE_URL:/INDEX/201912/23/C2590INRP02.TXT 0 -1 1) "1577032690000 20191223003801 \\C1695A1CPK1\\C19CL\\C19CL01A\\C19CL01ACJ\\FORMAT\\C2590C19CL01ACJ.TXT#003810 1" 2) "1577033573000 20191223005243 \\C1695A1CPK1\\C19CJ\\C19CJ00A\\C19CJ00AAX\\FORMAT\\C2590C19CJ00AAX.TXT#005253 2" 3) "1577033621000 20191223005332 \\C1695A1CPK1\\C19CF\\C19CF04N\\C19CF04NAJ\\FORMAT\\C2590C19CF04NAJ.TXT#005342 3" 4) "1577033697000 20191223005452 \\C1695A1CPK1\\C19CK\\C19CK02M\\C19CK02MBP\\FORMAT\\C2590C19CK02MBP.TXT#005457 5" 5) "1577049900000 20191223052333 \\C1695A1CPK1\\C19CK\\C19CK03Q\\C19CK03QAQ\\FORMAT\\C2590C19CK03QAQ-1.TXT#052500 24" 6) "1577049981000 20191223052612 \\C1695A1CPK1\\C19BE\\C19BE061\\C19BE061BA\\FORMAT\\C2590C19BE061BA.TXT#052621 30" 7) "1577051094000 20191223054446 \\C1695A1CPK1\\C19CL\\C19CL01A\\C19CL01ACJ\\FORMAT\\C2590C19CL01ACJ-1.TXT#054454 104" 8) "1577051568000 20191223055239 \\C1695A1CPK1\\C19CK\\C19CK00N\\C19CK00NBL\\FORMAT\\C2590C19CK00NBL-1.TXT#055248 126" 9) "1577051639000 20191223055350 \\C1695A1CPK1\\C19CK\\C19CK02M\\C19CK02MBP\\FORMAT\\C2590C19CK02MBP-1.TXT#055359 128" 10) "1577051811000 20191223055642 \\C1695A1CPK1\\C19CG\\C19CG018\\C19CG018AP\\FORMAT\\C2590C19CG018AP-1.TXT#055651 132" 11) "1577051933000 20191223055844 \\C1695A1CPK1\\C19CF\\C19CF04N\\C19CF04NAJ\\FORMAT\\C2590C19CF04NAJ-1.TXT#055853 134"
zrangebyscore(key, min, max):返回名称为key的zset中score >= min且score <= max的所有元素
Key:result:glass_id
Value:actualEqptId,actualSubEqptId,defectCnt,glassId,ifPreProcess,OOC,OOS,panelCnt,preOpeId,processEndTime,ruleSeqId Score:rule_id 查询命令:zrangebyscore result:A19C905MAL 269733 269733Key:history:站点
Value:主机台:子机台:recipe:prod:lot:glass:当前时间:F Score:该片glass的ProcEndTime时间 查询命令:zrangebyscore history:A2353 1576544400 1576548000
显示整个有序集ZRANGEBYSCORE history:ope -inf +inf[root@P1QMSPL2RTM01 log]# redis-cli -p 6379 zrangebyscore history:C7777 -inf +inf 1) "CHAN0300:CHAN0300:null:C1495A1ANK1:C189B031N00:C188900TBA:M" 2) "CHAN0300:CHAN0300:null:C1495A1ANK1:C189B031N00:C188W02NBD:M" 3) "CHAN0300:CHAN0300:null:C1495A1ANK1:C189B03XN00:C188S01TBT:M" 4) "CHAN0300:CHAN0300:null:C1495A1ANK1:C189B03XN00:C188U021BV:M" 5) "CHAN0300:CHAN0300:null:C1495A1ANK1:C189B03XN00:C1891023BH:M" 6) "CHAN0300:CHAN0300:null:C1495A1ANK1:C189B03XN00:C189200SBN:M" 7) "CHAN0300:CHAN0300:null:C1495A1ANK1:C189B03XN00:C189200SBS:M" 8) "CHAN0300:CHAN0300:null:C1495A1ANK1:C189B03XN00:C1893008BN:M" 9) "CHAN0300:CHAN0300:null:C1495A1ANK1:C189B055N00:C189300HAQ:M"10) "CHAN0300:CHAN0300:null:C1495A1ANK1:C189B05PN00:C188W02SBT:M"显示整个有序集及成员的 score 值-inf 负无穷+inf 正无穷ZRANGEBYSCORE history:ope -inf +inf WITHSCORES [root@P1QMSPL2RTM01 log]# redis-cli -p 6379 zrangebyscore history:C7777 -inf +inf withscores 1) "CHAN0300:CHAN0300:null:C1495A1ANK1:C189B031N00:C188900TBA:M" 2) "1536626081" 3) "CHAN0300:CHAN0300:null:C1495A1ANK1:C189B031N00:C188W02NBD:M" 4) "1536626081" 5) "CHAN0300:CHAN0300:null:C1495A1ANK1:C189B03XN00:C188S01TBT:M" 6) "1536633079" 7) "CHAN0300:CHAN0300:null:C1495A1ANK1:C189B03XN00:C188U021BV:M" 8) "1536633079" 9) "CHAN0300:CHAN0300:null:C1495A1ANK1:C189B03XN00:C1891023BH:M"10) "1536633079"11) "CHAN0300:CHAN0300:null:C1495A1ANK1:C189B03XN00:C189200SBN:M"12) "1536633079"13) "CHAN0300:CHAN0300:null:C1495A1ANK1:C189B03XN00:C189200SBS:M"14) "1536633079"15) "CHAN0300:CHAN0300:null:C1495A1ANK1:C189B03XN00:C1893008BN:M"16) "1536633079"17) "CHAN0300:CHAN0300:null:C1495A1ANK1:C189B055N00:C189300HAQ:M"18) "1536644040"19) "CHAN0300:CHAN0300:null:C1495A1ANK1:C189B05PN00:C188W02SBT:M"20) "1536648516"
zrem(key, member) :删除名称为key的zset中的元素member
例如删除history:ope 17S - 18E的所有数据
zremrangebyscore history:A2355 1483200000 1546271999
zcard(key):返回名称为key的zset该key的value数量
127.0.0.1:6380> zcard testKey(integer) 4
pipeline 的默认的同步的个数为53个,也就是说arges中累加到53条数据时会把数据提交
-----------------------------------------------update 2019年8月10日10:30:18-----------------------------------
类似于key 从链表的两端取出数据。
lrange(key, start, end):返回名称为key的list中start至end之间的元素(下标从0开始)
lrange key 0 -1 表示返回的时该key的所有数据,0代表起始 ,-1代表最后元素。(正负双向索引)
Key:opehis:glassId
Value:站点:主机台:子机台:prod:ProcEndTime:当前时间:F 查询命令:lrange opehis:A19C905MAL 0 -1
rpush(key, value):在名称为key的list尾添加一个值为value的元素( r 代表右)
String opeValue = String.format("%s:%s:%s:%s:%s:%s:%s",opeId, eqptId, eqptId,prodId, epochSecond, evtTime, "F");String opeKey = String.format("opehis:%s", glassId);jedis.rpush(opeKey,opeValue);
rpop(key):返回并删除名称为key的list中的尾元素
lpush(key, value):在名称为key的list头添加一个值为value的 元素( l代表左)
Note: 允许重复元素,例如opehis:glass 此key
lpop(key):返回并删除名称为key的list中的首元素
应用: "查看全文 "时候只show 一部分数据,当点击查看全文的时候再去DB获取。(这种设计非常合理,因为用户愿意点击查看全文就意味着用户愿意花费时间去等待获取需要的内容)
String是最常用的一种数据类型,普通的key/value存储.
比较适用于列表式存储且顺序相对比较固定,例如:
省份、城市列表
品牌、厂商、车系、车型等列表
拆车坊专题列表...
Set对外提供的功能与list类似,当需要存储一个列表数据,又不希望出现重复数据时,可选用set
zset的使用场景与set类似,区别是set不是自动有序的,而zset可以通过用户额外提供一个优先级(score)的参数来为成员排序,并且是插入有序的,即自动排序.当你需要一个有序的并且不重复的集合列表,那么可以选择zset数据结构。例如:
根据PV排序的热门车系车型列表
根据时间排序的新闻列表
C语言中的字符串是根据特殊字符“\0”来判断该字符串是否结束,对于字符串str="0123456789\0123456789”来说,在C语言里面str的长度就是10(strlen(str)=10),所以strlen()函数不是二进制安全的。而在Redis中,strlen str的结果是21,是二进制安全的(Redis底层所使用的字符串表示是Sds),它只关心二进制化的字符串,不关心字符串的具体格式,里面有啥字符,只会严格的按照二进制的数据存取,不会以某种特殊格式解析字符串。
转载地址:http://fkeqj.baihongyu.com/