Redis我想入门——数据类型
每一个数据库都有自己的数据类型。同样子redis为我们提供了五种类型的数据——字符串、哈希、列表、集合、有序集合。我们知道关系型数据的数据存放型式是一张二维表。用行和列来表示数据之间的关系。redis是一个nosql数据库当然不可能在用什么二维表的形式来表示了。他所有的数据都是以key=value的形式来存放的。每一种数据类型都有数据结构和内部编码的概念。数据结构你们可以理解他们的存放时的结构。而内部编码就是数据结构的具体实现。但是一种数据结构可以对应多种内部编码的实现。接下来笔者就要去看看每一种数据类型相关的操作命令和数据结构,内部编码。
1.字符串类型的数据
字符串类型,笔者认为比较简单的类型。
数据结果:一串值
内部编码:一共有三种:int embstr raw
例子:
127.0.0.1:6379> set k1 1002 OK 127.0.0.1:6379> set k2 "i am aomi" OK 127.0.0.1:6379> set k3 "i am aomi i am aomi i am aomi i am aomi i am aomi i am aomi i am aomi i am aomi i am aomi i am aomi i am aomi " OK 127.0.0.1:6379> object encoding k3 "raw" 127.0.0.1:6379> object encoding k2 "embstr" 127.0.0.1:6379> object encoding k1 "int" 127.0.0.1:6379> keys * 1) "k3" 2) "k1" 3) "k2" 127.0.0.1:6379> get k2 "i am aomi"
笔者向redis时面存放了三个值。他这三个值对应的键为:k1、k2、k3。
- set:用于增加字串符的值。
语法:
SET key value [EX seconds] [PX milliseconds] [NX|XX]
key:键名
value:键对应的值
EX:表示有效的时间。0表示永存,大于0表示在几秒内有效。
PX:表示有效时间。只是单位是毫秒。
NX:表示不存在的时候才可以增加成功。
XX:表示只有存在的时候才可以增加成功。
- object encoing:用于查看当前键的内部编码。
语法:
OBJECT subcommand [arguments [arguments]]
subcommand:这个有三个值 refcount(用于查看对象引用次数)、encoding(查看内部编码)、idletime(存在的时间)。
- keys:用于查看当前数据库有多少键。
语法:
KEYS pattern
pattern:*表示全部。*aaa表示查找以aaa结尾的。[a,b]123表示查看以a或是b,并且后面是123。相信不用笔者都说明了。
- get:用于获取指定键的值。
语法:
GET key
key:键的名称
学下语法之后,我们可以从上面看到字串符有三种内部编码了吧。如果你输入是一个数字的话,一般都是int。如果输入不是一个数字的话,是embstr。如果输入的字符串长度大于512的话。就会变成raw
笔者来一个设置有效时间的数据吧。
127.0.0.1:6379> set k5 v5 ex 10 OK 127.0.0.1:6379> ttl k5 (integer) 4 127.0.0.1:6379> ttl k5 (integer) -2
上面ttl用于查看当前键是的有效时间。
上面的都是一个一个增加有没有一次增加多个呢?当然是有的。
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 OK 127.0.0.1:6379> mget k1 k2 k3 1) "v1" 2) "v2" 3) "v3" 127.0.0.1:6379>
事实上学习redis的命令是一件很简单的事情。笔者是一边看命令手册一边写命令的。所以大家也可以这样子。自己写过一遍基本上都不会忘记。如果有不懂的话,查看一下手册就可以了。至于手册网络上很多。建义可以去官网看看。
2.哈希类型的数据
这个数据类型算是这五种类型中最为复杂的。存放形式不用说key=value。只是这个value里面就不一样子。是一个field=value形式的数据值。
数据结构:key: value(field=value)。不知道笔者这样子表示你们看得懂多。
内部编码:一共有俩种。一种是ziplist,二种是hashtable。
列子:
127.0.0.1:6379> hset user:1 name aomi (integer) 1 127.0.0.1:6379> hset user:1 age 32 (integer) 1 127.0.0.1:6379> hset user:1 sex 1 (integer) 1 127.0.0.1:6379> hset user:2 name nono (integer) 1 127.0.0.1:6379> hset user:2 age 24 (integer) 1 127.0.0.1:6379> hset user:2 sex 1 (integer) 1 127.0.0.1:6379> hset user:2 desc "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" (integer) 1 127.0.0.1:6379> hget user:1 name "aomi" 127.0.0.1:6379> hkeys user:1 1) "name" 2) "age" 3) "sex" 127.0.0.1:6379> hvals user:1 1) "aomi" 2) "32" 3) "1" 127.0.0.1:6379> hgetall user:1 1) "name" 2) "aomi" 3) "age" 4) "32" 5) "sex" 6) "1" 127.0.0.1:6379> object encoding user:1 "ziplist" 127.0.0.1:6379> object encoding user:2 "hashtable" 127.0.0.1:6379>
笔者先向redis数据库增加俩个数据。分别为:user:1 和user:2。同时写了三个获得哈希信息的命令。分别为:hget 、hkeys、hvals、hgetall。接着显示出这个俩数据的内部编码。
- hset:用于增加哈希
语法:
HSET key field value
从语法我就可以看出数据结构大概是一个什么样子。这个JAVA的类有一个像。key为类名,field为成员,value:为成员的值。事实上你可以看到笔者上面的例子就有一点像存放User类的实例一样子。
key:键名称
field:成员名
value:成员的值
- hget:用于获得一个成员的值。
语法:
HGET key field
- hkeys:用于获得当前键下的所有成员
语法:
HKEYS key
- hvals:用于获得当前键下的所有值
语法:
HVALS key
- hgetall:用于获得当前键下的所有成员和对应的所有值。
语法:
HGETALL key
上面例子我们可以看到俩种内部编码。user:2的desc却很长。一定大于64个字节。什么意思。如果成员值的长度大于64个字节的话,内部编码都会转为hashtable。当然还有如果你的成员个数大于512的话,内部编码也会转为hashtable有话。
笔者想知如果user:2的desc成员删除。内部编号会不会为ziplist。同时大家看一下什么删除。
127.0.0.1:6379> hdel user:2 desc (integer) 1 127.0.0.1:6379> object encoding user:2 "hashtable" 127.0.0.1:6379> hkeys user:2 1) "name" 2) "sex" 3) "age" 127.0.0.1:6379> hdel user:2 (error) ERR wrong number of arguments for 'hdel' command
最后一步出错了。笔者就想试一下删除整个键。你们看到出错了。要删除的话。还要用下的。
127.0.0.1:6379> del user:2 (integer) 1 127.0.0.1:6379> exists user:2 (integer) 0
这里有一个观念。hdel删除的是对应哈希里面的成员的。而要删除key是属于数据层的。
3.列表类型的数据
redis的列表有一点奇怪。在笔者第一接触的时候。被搞得有一点晕。你们可以这样子理解。现在有一个列表。他只有俩个地方可以进入。一个是左边的头,一个是右边的头。出去也只这俩个头。
数据结果:一个列表
内部编码:有三种:一种是ziplist,一个是linkedlist。最后一种是quicklist。
127.0.0.1:6379> lpush list1 a b c d e f (integer) 6 127.0.0.1:6379> lrange list1 0 -1 1) "f" 2) "e" 3) "d" 4) "c" 5) "b" 6) "a" 127.0.0.1:6379>
- lpush:将一个或多个值 从左边插入
语法:
LPUSH key value [value ...]
lpush就是从左边口进入。所以就 a进完 ,b在进,b进完了c进。以此类推。这个时候我们要以看到列表如下
左边进入--> f-e-d-c-b-a
- lrange:获得指定区间内的元素。
语法:
LRANGE key start stop
start表示从哪里开始,stop表示从哪里结果,如果stop=-1表示最后一个,-2的话表示倒数第二个,-3的话表示倒数第三个,依此类推。
现在我们就可以明白为什么上面是f-e-d-c-b-a。我们在来看看从右边插入会是什么样子。
127.0.0.1:6379> rpush list2 1 2 3 4 5 6 7 (integer) 7 127.0.0.1:6379> lrange list2 0 -1 1) "1" 2) "2" 3) "3" 4) "4" 5) "5" 6) "6" 7) "7" 127.0.0.1:6379>
如果我们从右边的口进入的话,那么在列表里就是如下
1-2-3-4-5-6-7 <--右边进入
所以lrange显示就是1,2,3,4,5,6,7。
列表的内部是有序的并且可以重复。笔者插入一个相同信的看看
127.0.0.1:6379> lpush list3 a a b c d (integer) 5 127.0.0.1:6379> lrange list3 0 -1 1) "d" 2) "c" 3) "b" 4) "a" 5) "a"
上面都是入,没有出。现在笔者要做一出的操作。如下
127.0.0.1:6379> lrange list1 0 -1 1) "f" 2) "e" 3) "d" 4) "c" 5) "b" 6) "a" 127.0.0.1:6379> lpop list1 "f" 127.0.0.1:6379> lrange list1 0 -1 1) "e" 2) "d" 3) "c" 4) "b" 5) "a" 127.0.0.1:6379>
我们发现用lpop的命令之后。相对应的值也会被取出。如上面的“f”就是被取出来了。笔者最后看一下列表只有:e-d-c-b-a了。原来应该是f-e-d-c-b-a。说明lpop是左边出的。同样子rpop是从右边出的。
127.0.0.1:6379> rpop list1 "a" 127.0.0.1:6379> lrange list1 0 -1 1) "e" 2) "d" 3) "c" 4) "b" 127.0.0.1:6379>
接下让我们看一下他的内部编码。
127.0.0.1:6379> lpush list4 a "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" (integer) 4 127.0.0.1:6379> object encoding list4 "quicklist" 127.0.0.1:6379> lrange list4 0 -1 1) "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" 2) "a" 3) "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 4) "a" 127.0.0.1:6379>
笔者用了很长的值,内部编码还是quicklist。quicklist是3.2版本之后出现的。他接结ziplist和linkedlist俩都优点而生的。相关的你们可以去查看官网。
redis提供列表的功能事实上是可以当队列和栈来用的。先进先出。那么你就要用到lpush和rpop 或是rpush 和lpop。从左边进,从右边出。后进先出就是栈了。那么就lpush和lpop或是rpush和rpop了。
4.集合类型的数据
他是一个无序的,同时他不能有重复。
数据结果:你可以理解为一个箱子。东西随便放。但不能重复。
内部编码:他有俩种:一是intset,一种hashtable.
例子
127.0.0.1:6379> sadd set1 a a b c d e f (integer) 6 127.0.0.1:6379> smembers set1 1) "a" 2) "d" 3) "c" 4) "f" 5) "b" 6) "e" 127.0.0.1:6379> object encoding set1 "hashtable" 127.0.0.1:6379> sadd set2 a b "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" (integer) 3 127.0.0.1:6379> object encoding set2 "hashtable" 127.0.0.1:6379> object encoding set1 "hashtable" 127.0.0.1:6379> sadd set3 1 2 3 4 5 6 7 8 9 (integer) 9 127.0.0.1:6379> smembers set3 1) "1" 2) "2" 3) "3" 4) "4" 5) "5" 6) "6" 7) "7" 8) "8" 9) "9" 127.0.0.1:6379> object encoding set3 "intset" 127.0.0.1:6379>
笔者增加了三个集合类型的数据。set1一般没有什么特别的。set2里面有一个值长度很长。set3都是整数。
- sadd:用于增加一个集合。
语法:
SADD key member [member ...]
笔者就不说明了。member就是相对应的成员值。
- smembers用于显示里面的成员
语法:
SMEMBERS key
笔者分别显示出三个的内部编码。发现只有当集合里面全部是整数的时候,内部编码是intset。其他都是hashtable。
5.有序集合类型的数据
你们可以这样子里面集合类型是无序的。为了让他有序,把集合类型的数据结构里面加入值来表示他的顺序。
数据结构:同样子的箱子。只是在放入这个箱子的东西。必须贴上相关的数字标签。
内部编码:有俩种:一种是ziplist,一种是skiplist。
127.0.0.1:6379> zadd stu 80 math 60 english 70 chinese (integer) 3 127.0.0.1:6379> zcard stu (integer) 3 127.0.0.1:6379> zrange stu 0 -1 1) "english" 2) "chinese" 3) "math" 127.0.0.1:6379> zrange stu 0 -1 withscores 1) "english" 2) "60" 3) "chinese" 4) "70" 5) "math" 6) "80" 127.0.0.1:6379> zadd stu2 80 "aoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" (integer) 1 127.0.0.1:6379> object encoding stu "ziplist" 127.0.0.1:6379> object encoding stu2 "skiplist" 127.0.0.1:6379>
有没有感觉就是一个报表。比如学习的成绩之类的数据体现。80分 数学。60分 语文。那么前面是不是一定要是一个数字呢?笔者做了一下实验。
127.0.0.1:6379> zadd stu3 "GODD" "AOMI" 80 EN (error) ERR value is not a valid float
看到了果然要一个数字。同时我们可以到他的俩种内部编码。