每一个数据库都有自己的数据类型。同样子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
看到了果然要一个数字。同时我们可以到他的俩种内部编码。