上一篇写了一个《Jedis操作Redis有序集合类型(SortedSet)》,对于实战来说当然是需要将Redis支持的五种类型都熟悉和了解的,接下来就是Jedis操作Redis的String类型。
Redis支持的字符串可以是(简单的字符串、复杂的字符串(例如JSON、XML))、数字(整数、浮点数),甚至是二进制(图片、音频、视频),但是值最大不能超过512MB !
然后来看看什么情况下会使用呢?
private void setStringValue(String key){
//新增key,成功返回 OK
String result = getJedis().set(key, "设置一个String值");
//根据key,获取值
getJedis().get(key);
//strlen 读取value长度 根据key获取到value的长度
Long strlen = getJedis().strlen(key);
//只有String类型的key才有的过期时间,设置过期时间为5秒
Long expire = getJedis().expire(key, 5);
//既然设置了过期时间,那么查看某个key的剩余生存时间,单位秒,永久生存或者不存在的都返回-1
Long ttlTime = getJedis().ttl(key);
//当然也可以移除某个key的生存时间
Long persist = getJedis().persist(key);
System.out.println("移除生存时间后 ttl of " + key + "=" + getJedis().ttl(key));
//查看key所储存的值的类型
String type = getJedis().type(key);
//一次性新增多个key
getJedis().mset("key001", "value001", "key002", "value002", "key003",
"value003", "key004", "value004");
//读取所有key,遍历,判断类型 字符匹配规则 可以是 XXX* 以XXX开头的key,当然可以使用正则表达式,但是不推荐
Set keys = getJedis().keys("*");
Iterator it = keys.iterator();
while (it.hasNext()) {
key = it.next();
if (getJedis().type(key).equals("string")){
System.out.println("读取所有key并筛选string类型 get " + key + "=" + getJedis().get(key));
}
}
//一次性获取多个key值
List list = getJedis().mget("key001", "key002", "key003", "key004");
System.out.println("一次性获取多个key值:"+list);
//一次性删除多个key参数为一个字符串数组,返回成功删除个数
Long del = getJedis().del(new String[] { "key001", "key002" });
// 禁止覆盖
Long setnx = getJedis().setnx("key003", "value003_new");
//新增key同时设置有效期(秒)
result = getJedis().setex(key, 3, "setex demo");
System.out.println("result"+result+"[4秒之前]get " + key + "=" + getJedis().get(key));
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
}
System.out.println("[4秒之后]get " + key + "=" + getJedis().get(key));
//获取原值, 更新为新值一步完成
key = "key003";
String former = getJedis().getSet(key, "value002-after-getset");
System.out.println("getSet 原值:" + former + "; 新值" + getJedis().get(key));
//incr 自增
key = "redis_num";
getJedis().del(key);
////如果key存在,则value的值为:key+1 如可以不存在,则生成value为0的key,再+1
long incr = getJedis().incr(key);
//与上面不同的是增加值是传进来的value 多为存储的value为数字
getJedis().incrBy(key, Integer.parseInt(value));
Long decr = getJedis().decrBy(key, 100);
//给某一个键 追加值
Long appendValue = getJedis().append(key, "appendValue");
//设置指定位置的字符 源redis 命令 setrange key offeset value 注意是字符
Long setrange = getJedis().setrange(key, 2, "special");
//获取部分字符串 getrange key start end
getJedis().getrange(key,0,10);
//Redis Incr 命令将 key 中储存的数字值增一,如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作,且将key的有效时间设置为长期有效。
//Redis Incrby 命令将 key 中储存的数字加上指定的增量值,如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。
//Redis Hincrby 命令用于为哈希表中的字段值加上指定增量值
}
其实Redis是巨大的Map是一个key-value的存储系统,其中Key类型一般都是为String,而Value的类型则为Redis 对象(redis object),所以可以绑定不同的类型,譬如 string、list 和set。
来说说String类型,String是Redis最基本的类型,而且String类型是二进制安全的。意思是Redis的string可以包含任何数据,比如jpg图片或者序列化的对象。从内部实现来看其实string可以看作byte数组,最大上限是1G字节。
struct sdshdr {
//buf 中已占用空间的长度
long len;
// buf 中剩余可用空间的长度
long free;
//字符数组 用于记录我们的字符串(记录Redis)
char buf[];
};
buf是个char数组用于存贮实际的字符串内容。其实char和c#中的byte是等价的,都是一个字节 ,len是buf数组的长度,free是数组中剩余可用字节数。 由此可以理解为什么string类型是二进制安全的了。因为它本质上就是个byte数组。当然可以包含任何数据了。 另外String类型可以被部分命令按int处理,比如incr等命令,Redis的其他类型像list,set,sorted set ,hash它们包含的元素与都只能是String类型。
Redis 中的字符为简单动态字符串(simple dynamic string SDS)的抽象类型,并将SDS用作Redis 的默认字符串。当我知道Redis的对象数据类型有5种,有4bits,然后对象的编码类型,占4bits,共10种类型,感觉Redis 也是面向对象的呢!
//type的占5种类型:
/* Object types */
#define OBJ_STRING 0 //字符串对象
#define OBJ_LIST 1 //列表对象
#define OBJ_SET 2 //集合对象
#define OBJ_ZSET 3 //有序集合对象
#define OBJ_HASH 4 //哈希对象
// encoding 的10种类型:
//原始表示方式,字符串对象是简单动态字符串
#define OBJ_ENCODING_RAW 0 /* Raw representation */
//long类型的整数
#define OBJ_ENCODING_INT 1 /* Encoded as integer */
//字典
#define OBJ_ENCODING_HT 2 /* Encoded as hash table */
//已经不使用
#define OBJ_ENCODING_ZIPMAP 3 /* Encoded as zipmap */
//双端链表,已经不使用
#define OBJ_ENCODING_LINKEDLIST 4 /* Encoded as regular linked list */
//压缩列表
#define OBJ_ENCODING_ZIPLIST 5 /* Encoded as ziplist */
//整数集合
#define OBJ_ENCODING_INTSET 6 /* Encoded as intset */
//跳跃表和字典
#define OBJ_ENCODING_SKIPLIST 7 /* Encoded as skiplist */
//embstr编码的简单动态字符串
#define OBJ_ENCODING_EMBSTR 8 /* Embedded sds string encoding */
//由压缩列表组成的双向列表-->快速列表
#define OBJ_ENCODING_QUICKLIST 9 /* Encoded as linked list of ziplists */
#不同类型和编码的对象
REDIS_STRING REDIS_ENCODING_INT 使用整数值实现的字符串对象。
REDIS_STRING REDIS_ENCODING_EMBSTR 使用 embstr 编码的简单动态字符串实现的字符串对象。
REDIS_STRING REDIS_ENCODING_RAW 使用简单动态字符串实现的字符串对象。
REDIS_LIST REDIS_ENCODING_ZIPLIST 使用压缩列表实现的列表对象。
REDIS_LIST REDIS_ENCODING_LINKEDLIST 使用双端链表实现的列表对象。
REDIS_HASH REDIS_ENCODING_ZIPLIST 使用压缩列表实现的哈希对象。
REDIS_HASH REDIS_ENCODING_HT 使用字典实现的哈希对象。
REDIS_SET REDIS_ENCODING_INTSET 使用整数集合实现的集合对象。
REDIS_SET REDIS_ENCODING_HT 使用字典实现的集合对象。
REDIS_ZSET REDIS_ENCODING_ZIPLIST 使用压缩列表实现的有序集合对象。
REDIS_ZSET REDIS_ENCODING_SKIPLIST 使用跳跃表和字典实现的有序集合对象。
#OBJECT ENCODING 对不同编码的输出
整数 REDIS_ENCODING_INT "int"
embstr 编码的简单动态字符串(SDS) REDIS_ENCODING_EMBSTR "embstr"
简单动态字符串 REDIS_ENCODING_RAW "raw"
字典 REDIS_ENCODING_HT "hashtable"
双端链表 REDIS_ENCODING_LINKEDLIST "linkedlist"
压缩列表 REDIS_ENCODING_ZIPLIST "ziplist"
整数集合 REDIS_ENCODING_INTSET "intset"
跳跃表和字典 REDIS_ENCODING_SKIPLIST "skiplist"
上面就是Redis的底层是数据结构,它们支撑起来了这个Key-Value的存储系统。然后我们看看String对应的编码:
字符串对象的编码可以是 INT、RAW 或 EMBSTR。如果保存的是整数值并且可以用long表示,那么编码会设置为INT。当字符串值得长度大于44字节使用RAW,小于等于44字节使用EMBSTR。
Redis在3.0引入EMBSTR编码,这是一种专门用于保存短字符串的一种优化编码方式,这种编码和RAW编码都是用sdshdr简单动态字符串结构来表示。RAW编码会调用两次内存分配函数来分别创建redisObject和sdshdr结构,而EMBSTR只调用一次内存分配函数来分配一块连续的空间保存数据,比起RAW编码的字符串更能节省内存,以及能提升获取数据的速度。
不过要注意!EMBSTR是不可修改的,当对EMBSTR编码的字符串执行任何修改命令,总会先将其转换成RAW编码再进行修改;而INT编码在条件满足的情况下也会被转换成RAW编码。
还要注意一点就是使用String类型是在存储/读取时需要进行序列化/反序列化的!