java散列类_散列类型_redis教程_田守枝Java技术博客

本文介绍了Redis的散列类型,作为存储和操作数据的高效手段,特别适合存储文章数据。散列类型允许单独操作字段,避免资源浪费,同时提供HSET、HGET等命令进行赋值和取值。通过散列类型,可以实现文章列表中仅显示标题的需求,提高数据传输效率。
摘要由CSDN通过智能技术生成

小白只用了半个多小时就把访问统计和发表文章两个部分做好了。同时借助Bootstrap框架,老师花了一小会儿时间教会了之前只涉猎过HTML的小白如何做出一个像样的网页界面。接着小白发问:

接下来我想要做的功能是博客的文章列表页,我设想在列表页中每个文章只显示标题部分,可是使用您刚才介绍的方法,若想取得文章的标题,必须把整个文章数据字符串取出来反序列化,而其中占用空间最大的文章內容部分却是不需要的,这样难道不会在传输和处理时造成资源浪费吗?

老师有些惊喜地看着小白答道:“很对!”同时以一个夸张的幅度点了下头,接着说:

这正是我接下来准备讲的。不仅取数据时会有资源浪费,在修改数据时也会有这个问题,比如当你只想更改文章的标题时也不得不把整个文章数据字符串更新一遍。

没等小白再问,老师就又继续说道:

前面我说过Redis的强大特性之一就是提供了多种实用的数据类型,其中的散列类型可以非常好地解决这个问题。

3.3.1 介绍

我们现在已经知道Redis是采用字典结构以键值对的形式存储数据的,而散列类型(hash)的键值也是一种字典结构,其存储了字段(field)和字段值的映射,但字段值只能是字符串,不支持其他数据类型,换句话说,散列类型不能嵌套其他的数据类型。一个散列类型键可以包含至多232-1个字段。

提示 除了散列类型,Redis的其他数据类型同样不支持数据类型嵌套。比如集合类型的每个元素都只能是字符串,不能是另一个集合或散列表等。

散列类型适合存储对象:使用对象类别和ID构成键名,使用字段表示对象的属性,而字段值则存储属性值。例如要存储ID为2的汽车对象,可以分别使用名为color、name和price的3个字段来存储该辆汽车的颜色、名称和价格。存储结构如图3-5所示。

2fb830776b39caa6e21ce4cde0505304.png

回想在关系数据库中如果要存储汽车对象,存储结构如表3-2所示。

fa098615d5685bdca4ac548f739f723c.png

数据是以二维表的形式存储的,这就要求所有的记录都拥有同样的属性,无法单独为某条记录增减属性。如果想为ID为1的汽车增加生产日期属性,就需要把数据表更改为如表3-3所示的结构。

20711e954bb28efb3c5b2de7ee9e2abb.png

对于ID为2和3的两条记录而言date字段是冗余的。可想而知当不同的记录需要不同的属性时,表的字段数量会越来越多以至于难以维护。

而Redis的散列类型则不存在这个问题。虽然我们在图3-5中描述了汽车对象的存储结构,但是这个结构只是人为的约定,Redis并不要求每个键都依据此结构存储,我们完全可以自由地为任何键增减字段而不影响其他键。

3.3.2 命令

1.赋值与取值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"

HSET命令的方便之处在于不区分插入和更新操作,这意味着修改数据时不用事先判断字段是否存在来决定要执行的是插入操作(update)还是更新操作(insert)。当执行的是插入操作时(即之前字段不存在)HSET命令会返回1,当执行的是更新操作时(即之前字段已经存在)HSET命令会返回0。更进一步,当键本身不存在时,HSET命令还会自动建立它。

提示在Redis中每个键都属于一个明确的数据类型,如通过HSET命令建立的键是散列类型,通过SET命令建立的键是字符串类型等。使用一种数据类型的命令操作另一种数据类型的键会提示错误:“ERR Operation against a key holding the wrong kind of value”。

注释:并不是所有命令都是如此,比如SET命令可以覆盖已经存在的键而不论原来键是什么类型。

当需要同时设置多个字段的值时,可以使用HMSET命令。例如,下面两条语句HSET key field1 value1

HSET key field2 value2

可以用HMSET命令改写成HMSET key field1 value1 field2 value2

相应地,HMGET命令可以同时获得多个字段的值:redis>HMGET car price name

1) "500"

2) "BMW"

如果想获取键中所有字段和字段值却不知道键中有哪些字段时(如3.3.1节介绍的存储汽车对象的例子,每个对象拥有的属性都未必相同)应该使用HGETALL命令。如:redis>HGETALL car

1) "price"

2) "500"

3) "name"

4) "BMW"

返回的结果是字段和字段值组成的列表,不是很直观,好在很多语言的Redis客户端会将HGETALL的返回结果封装成编程语言中的对象,处理起来就非常方便了。

2.判断字段是否存在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

3.当字段不存在时赋值HSETNX key field value

HSETNXH 命令与HSET命令类似,区别在于如果字段已经存在,HSETNX命令将不执行任何操作。其实现可以表示为如下伪代码:

注释:HSETNX 中的“NX”表示“if Not eXists”(如果不存在)。def hsetnx( key, field, value)

isExists=HEXISTS key, field

if isExists is 0

HSET key, field, value

return 1

else

return 0

只不过HSETNX命令是原子操作,不用担心竞态条件。

4.增加数字

HINCRBY key field increment

上一节的命令拾遗部分介绍了字符串类型的命令INCRBY,HINCRBY命令与之类似,可以使字段值增加指定的整数。散列类型没有HINCR命令,但是可以通过HINCRBY key field 1来实现。

HINCRBY命令的示例如下:redis>HINCRBY person score 60

(integer) 60

之前person键不存在,HINCRBY命令会自动建立该键并默认score字段在执行命令前的值为“0”。命令的返回值是增值后的字段值。

5.删除字段

HDEL key field [field …]

HDEL命令可以删除一个或多个字段,返回值是被删除的字段个数:redis>HDEL car price

(integer) 1

redis>HDEL car price

(integer) 0

3.3.3 实践

1.存储文章数据

3.2.3节介绍了可以将文章对象序列化后使用一个字符串类型键存储,可是这种方法无法提供对单个字段的原子读写操作支持,从而产生竞态条件,如两个客户端同时获得并反序列化某个文章的数据,然后分别修改不同的属性后存入,显然后存入的数据会覆盖之前的数据,最后只会有一个属性被修改。另外如小白所说,即使只需要文章标题,程序也不得不将包括文章内容在内的所有文章数据取出并反序列化,比较消耗资源。除此之外,还有一种方法是组合使用多个字符串类型键来存储一篇文章的数据,如图3-6所示。

163bff3a3632679ecfa04c8fe6d61b15.png

使用这种方法的好处在于无论获取还是修改文章数据,都可以只对某一属性进行操作,十分方便。而本章介绍的散列类型则更适合此场景,使用散列类型的存储结构如图3-7所示。

1f5a3a7f4c856ea9675f2732516c92e5.png

从图3-7可以看出使用散列类型存储文章数据比图3-6所示的方法看起来更加直观也更容易维护(比如可以使用HGETALL命令获得一个对象的所有字段,删除一个对象时只需要删除一个键),另外存储同样的数据散列类型往往比字符串类型更加节约空间,具体的细节会在4.6节中介绍。

2.存储文章缩略名

使用过WordPress的读者可能会知道发布文章时一般需要指定一个缩略名(slug)来构成该篇文章的网址的一部分,缩略名必须符合网址规范且最好可以与文章标题含义相似,如“This Is A Great Post!”的缩略名可以为“this-is-a-great-post”。每个文章的缩略名必须是唯一的,所以在发布文章时程序需要验证用户输入的缩略名是否存在,同时也需要通过缩略名获得文章的ID。

我们可以使用一个散列类型的键slug.to.id来存储文章缩略名和ID之间的映射关系。其中字段用来记录缩略名,字段值用来记录缩略名对应的ID。这样就可以使用HEXISTS命令来判断缩略名是否存在,使用HGET命令来获得缩略名对应的文章ID了。

3.3.4 命令拾遗

1.只获取字段名或字段值

HKEYS key

HVALS key

有时仅仅需要获取键中所有字段的名字而不需要字段值,那么可以使用HKEYS命令,就像这样:redis>HKEYS car

1) "name"

2) "model"

HVALS命令与HKEYS命令相对应,HVALS命令用来获得键中所有字段值,例如:redis>HVALS car

1) "BMW"

2) "C200"

2.获得字段数量

HLEN key

例如:redis>HLEN car

(integer) 2

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JedisUtil是一个Java Redis缓存工具,它封装了Jedis客户端的基本操作,使得使用Redis缓存更加简单方便。 以下是JedisUtil的示例代码: ``` import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; public class JedisUtil { private static JedisPool jedisPool; static { JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); jedisPoolConfig.setMaxTotal(1000); jedisPoolConfig.setMaxIdle(100); jedisPool = new JedisPool(jedisPoolConfig, "localhost", 6379); } public static void set(String key, String value) { try (Jedis jedis = jedisPool.getResource()) { jedis.set(key, value); } } public static String get(String key) { try (Jedis jedis = jedisPool.getResource()) { return jedis.get(key); } } public static void del(String key) { try (Jedis jedis = jedisPool.getResource()) { jedis.del(key); } } public static void expire(String key, int seconds) { try (Jedis jedis = jedisPool.getResource()) { jedis.expire(key, seconds); } } public static boolean exists(String key) { try (Jedis jedis = jedisPool.getResource()) { return jedis.exists(key); } } } ``` 在上面的代码中,我们使用了JedisPool来管理Jedis连接,它的作用是维护一定数量的Jedis连接,以便在需要时从池中获取连接,减少了创建和关闭连接的开销。 在使用JedisUtil时,我们只需要调用set、get、del、expire和exists等方法,就可以完成对Redis缓存的操作。 例如,要将一个键值对("name", "Tom")存入Redis中,可以使用以下代码: ``` JedisUtil.set("name", "Tom"); ``` 要获取键为"name"的值,可以使用以下代码: ``` String name = JedisUtil.get("name"); ``` 同时,JedisUtil还提供了删除、设置过期时间和判断键是否存在等方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值