[b]3.3 散列类型[/b]
[b]3.3.1 介绍[/b]
Redis是采用字典结构以键值对的形式存储数据的,而散列类型(hash)的键值也是一种字典结构,其存储了字段(field)和字段值的映射,但[color=red]字段值只能是字符串[/color],不支持其他数据类型,换句话说,散列类型[color=red]不能嵌套其他的数据类型[/color]。一个散列类型键可以包含至多2^32-1个字段。
[b]提示: [/b]
除了散列类型,Redis的其他数据类型同样不支持数据类型嵌套。比如集合类型的每个元素都只能是字符串,不能是另一个集合或散列表等。
散列类型适合存储对象:使用对象类别和ID构成键名,使用字段表示对象的属性,而字段值则存储属性值。例如要存储ID为2的汽车对象,可以分别使用名为color、name和price的3个字段来存储该辆汽车的颜色、名称和价格。存储结构如图3-5所示。
[img]http://dl2.iteye.com/upload/attachment/0106/6498/4b66d2d4-6549-36dc-ae7c-43b5f69c3759.png[/img]
回想在关系数据库中如果要存储汽车对象,存储结构如下表所示。
[img]http://dl2.iteye.com/upload/attachment/0106/6500/a0a74259-d99f-3bdd-ab70-cf0f459a3b31.png[/img]
数据是以二维表的形式存储的,这就要求所有的记录都拥有同样的属性,无法单独为某条记录增减属性。如果想为ID为1的汽车增加生产日期属性,就需要把数据表更改为如下表所示的结构。
[img]http://dl2.iteye.com/upload/attachment/0106/6502/0cc32a9c-159c-352e-b8e3-cc197c88f976.png[/img]
对于ID为2和3的两条记录而言date字段是冗余的。可想而知当不同的记录需要不同的属性时,表的字段数量会越来越多以至于难以维护。而且当使用ORM将关系数据库中的对象实体映射成程序中的实体时,修改表的结构往往意味着要中断服务(重启网站程序)。为了防止这些问题,在关系数据库中存储这种半结构化数据还需要额外的表才行。
而Redis的散列类型则不存在这个问题。虽然我们在图3-5中描述了汽车对象的存储结构,但是这个结构只是人为的约定,Redis并不要求每个键都依据此结构存储,我们完全可以自由地为任何键增减字段而不影响其他键。
[b]3.3.2 命令[/b]
[b]1.赋值与取值[/b]
HSET命令用来给字段赋值,而HGET命令用来获得字段的值。
用法如下:
[color=red]HSET[/color]命令的方便之处在于[color=red]不区分插入和更新操作[/color],这意味着修改数据时[b]不用[/b]事先判断字段是否存在来决定要执行的是插入操作(update)还是更新操作(insert)。当执行的是插入操作时(即之前字段不存在)HSET命令会返回1,当执行的是更新操作时(即之前字段已经存在)HSET命令会返回0。更进一步,当键本身不存在时,HSET命令还会自动建立它。下面还会介绍一个hsetnx命令,就只是在键不存在的时候才赋值。
[b]提示:[/b]
在Redis中每个键都属于一个明确的数据类型,如通过HSET命令建立的键是散列类型,通过SET命令建立的键是字符串类型等。使用一种数据类型的命令操作另一种数据类型的键会提示错误:“ERR Operation against a key holding the wrong kind of value”① 。
[b]注释:[/b]①并不是所有命令都是如此,比如SET命令可以覆盖已经存在的键而不论原来键是什么类型。
如果想获取键中所有字段和字段值却不知道键中有哪些字段时(如3.3.1节介绍的存储汽车对象的例子,每个对象拥有的属性都未必相同)应该使用HGETALL命令。如:
返回的结果是字段和字段值组成的列表,不是很直观,好在很多语言的Redis客户端会将HGETALL的返回结果封装成编程语言中的对象,处理起来就非常方便了。
[b]2.判断字段是否存在[/b]
HEXISTS命令用来判断一个字段是否存在。如果存在则返回1,否则返回0(如果键不存在也会返回0)。
[b]3.当字段不存在时赋值[/b]
HSETNX① 命令与HSET命令类似,区别在于如果字段已经存在,HSETNX命令将不执行任何操作。HSETNX命令是原子操作,不用担心竞态条件。
[b]4.增加数字[/b]
HINCRBY命令与INCRBY类似,可以使字段值增加指定的整数。散列类型没有HINCR命令,但是可以通过HINCRBY keyfield 1来
实现。
HINCRBY命令的示例如下:
之前person键不存在,HINCRBY命令会自动建立该键并默认score字段在执行命令前的值为“0”。命令的返回值是增值后的字段值。
[b]5.删除字段[/b]
HDEL命令可以删除一个或多个字段,返回值是被删除的字段个数:
[b]6.只获取字段名或字段值[/b]
有时仅仅需要获取键中所有字段的名字而不需要字段值,那么可以使用HKEYS命令,就像这样:
HVALS命令与HKEYS命令相对应,HVALS命令用来获得键中所有字段值,例如:
[b]7. 获得字段数量[/b]
例如:
[b]3.3.1 介绍[/b]
Redis是采用字典结构以键值对的形式存储数据的,而散列类型(hash)的键值也是一种字典结构,其存储了字段(field)和字段值的映射,但[color=red]字段值只能是字符串[/color],不支持其他数据类型,换句话说,散列类型[color=red]不能嵌套其他的数据类型[/color]。一个散列类型键可以包含至多2^32-1个字段。
[b]提示: [/b]
除了散列类型,Redis的其他数据类型同样不支持数据类型嵌套。比如集合类型的每个元素都只能是字符串,不能是另一个集合或散列表等。
散列类型适合存储对象:使用对象类别和ID构成键名,使用字段表示对象的属性,而字段值则存储属性值。例如要存储ID为2的汽车对象,可以分别使用名为color、name和price的3个字段来存储该辆汽车的颜色、名称和价格。存储结构如图3-5所示。
[img]http://dl2.iteye.com/upload/attachment/0106/6498/4b66d2d4-6549-36dc-ae7c-43b5f69c3759.png[/img]
回想在关系数据库中如果要存储汽车对象,存储结构如下表所示。
[img]http://dl2.iteye.com/upload/attachment/0106/6500/a0a74259-d99f-3bdd-ab70-cf0f459a3b31.png[/img]
数据是以二维表的形式存储的,这就要求所有的记录都拥有同样的属性,无法单独为某条记录增减属性。如果想为ID为1的汽车增加生产日期属性,就需要把数据表更改为如下表所示的结构。
[img]http://dl2.iteye.com/upload/attachment/0106/6502/0cc32a9c-159c-352e-b8e3-cc197c88f976.png[/img]
对于ID为2和3的两条记录而言date字段是冗余的。可想而知当不同的记录需要不同的属性时,表的字段数量会越来越多以至于难以维护。而且当使用ORM将关系数据库中的对象实体映射成程序中的实体时,修改表的结构往往意味着要中断服务(重启网站程序)。为了防止这些问题,在关系数据库中存储这种半结构化数据还需要额外的表才行。
而Redis的散列类型则不存在这个问题。虽然我们在图3-5中描述了汽车对象的存储结构,但是这个结构只是人为的约定,Redis并不要求每个键都依据此结构存储,我们完全可以自由地为任何键增减字段而不影响其他键。
[b]3.3.2 命令[/b]
[b]1.赋值与取值[/b]
HSET key field value
HGET key field
HMSET key field value [field value …]
HMGET key field [field …]
HGETALL key
HSET命令用来给字段赋值,而HGET命令用来获得字段的值。
用法如下:
redis>HSET car price 500
(integer) 1
redis>HSET car name BMW
(integer) 1
redis>HGET car name
"BMW"
[color=red]HSET[/color]命令的方便之处在于[color=red]不区分插入和更新操作[/color],这意味着修改数据时[b]不用[/b]事先判断字段是否存在来决定要执行的是插入操作(update)还是更新操作(insert)。当执行的是插入操作时(即之前字段不存在)HSET命令会返回1,当执行的是更新操作时(即之前字段已经存在)HSET命令会返回0。更进一步,当键本身不存在时,HSET命令还会自动建立它。下面还会介绍一个hsetnx命令,就只是在键不存在的时候才赋值。
[b]提示:[/b]
在Redis中每个键都属于一个明确的数据类型,如通过HSET命令建立的键是散列类型,通过SET命令建立的键是字符串类型等。使用一种数据类型的命令操作另一种数据类型的键会提示错误:“ERR Operation against a key holding the wrong kind of value”① 。
[b]注释:[/b]①并不是所有命令都是如此,比如SET命令可以覆盖已经存在的键而不论原来键是什么类型。
如果想获取键中所有字段和字段值却不知道键中有哪些字段时(如3.3.1节介绍的存储汽车对象的例子,每个对象拥有的属性都未必相同)应该使用HGETALL命令。如:
redis>HGETALL car
1) "price"
2) "500"
3) "name"
4) "BMW"
返回的结果是字段和字段值组成的列表,不是很直观,好在很多语言的Redis客户端会将HGETALL的返回结果封装成编程语言中的对象,处理起来就非常方便了。
[b]2.判断字段是否存在[/b]
HEXISTS key field
HEXISTS命令用来判断一个字段是否存在。如果存在则返回1,否则返回0(如果键不存在也会返回0)。
redis>HEXISTS car model
(integer) 0
redis>HSET car model C200
(integer) 1
redis>HEXISTS car model
(integer) 1
[b]3.当字段不存在时赋值[/b]
HSETNX key field value
HSETNX① 命令与HSET命令类似,区别在于如果字段已经存在,HSETNX命令将不执行任何操作。HSETNX命令是原子操作,不用担心竞态条件。
[b]4.增加数字[/b]
HINCRBY key field increment
HINCRBY命令与INCRBY类似,可以使字段值增加指定的整数。散列类型没有HINCR命令,但是可以通过HINCRBY keyfield 1来
实现。
HINCRBY命令的示例如下:
redis>HINCRBY person score 60
(integer) 60
之前person键不存在,HINCRBY命令会自动建立该键并默认score字段在执行命令前的值为“0”。命令的返回值是增值后的字段值。
[b]5.删除字段[/b]
HDEL key field [field …]
HDEL命令可以删除一个或多个字段,返回值是被删除的字段个数:
redis>HDEL car price
(integer) 1
redis>HDEL car price
(integer) 0
[b]6.只获取字段名或字段值[/b]
HKEYS key
HVALS key
有时仅仅需要获取键中所有字段的名字而不需要字段值,那么可以使用HKEYS命令,就像这样:
redis>HKEYS car
1) "name"
2) "model"
HVALS命令与HKEYS命令相对应,HVALS命令用来获得键中所有字段值,例如:
redis>HVALS car
1) "BMW"
2) "C200"
[b]7. 获得字段数量[/b]
HLEN key
例如:
redis>HLEN car
(integer) 2