Redis学习笔记之五:散列类型
2017-11-01 17:50
441 查看
Redis的散列类型可以看做Java中的Map结构,后文简称Map,同时Redis中操纵Map的指令均已H开头。一个散列类型可以存储2的32次方-1个字段,即内部Key-Value的对数。
可以将Map当做Java中的HashMap,这样便于快速理解。既然将其看做Map,那Redis的这个Map肯定与Java中的Map有相似之处,如下图:
可以看到Key对应的Value是一个Map,而Map内部又有Key-Value键值对。内部的Key也是不能重复的,Value的值也是会被覆盖的。
1、设值/取值(put/get)
使用HSET与HGET获取Map的值,当然,与String类型一样,Map也能一次性获取多个或者设置多个值(HMSET/HMGET)。但设置多个值时,Key-Value一定要成对出现。否则当前指令会执行失败,原Map不会有任何改变。
可以看到取出来的值是String类型的。同时Key的值没有重复,且Value的值会被覆盖,如果获取的Key对应Map的key不存在,则会返回nil。
还有一点值得注意的是HSET,如果是插入新的Key-Value返回的是1,如果是修改旧的Value,返回是0.
2、获取Map内部的Key-Value对数(Map的size())。
使用HLEN指令可以获取指定的Map的Key-Value对数。同时,这个指令与STRLEN和LLEN指令一致,会在Key不存在时返回0.
3、获取Map的所有Key或者所有Value
指令HKEYS获取指定Map的所有Key,与Java中Map的KeySet一致。
指令KVALS获取指定Map的所有Value,在Java的Map中,对应values(),但有所不同。
示例如下:
4、获取Map的所有Key-Value。
可以使用指令HGETALL获取Map的所有Key-Value,与之对应的方法是Java中Map的entrySet方法。演示如下
单行为Key,双行为Value,获取不存在的Redis的Key,返回empty list,可以从提示信息看到,这个指令是将Map遍历然后转换成List类型呈现。
5、判断Map中的Key是否存在(containsKey)
指令用于HEXISTS用于判断Map中对应的Key是否存在。演示如下
我的Redis中是没有Key1这个键存在的,可以看到使用HEXISTS返回0表示Map中没有这个键,但也有可能是这个Map根本不存在。
6、删除Map中的Key(remove)
使用HDEL指令删除Map中的Key,格式HDEL map field。演示如下:
这个指令是可以跟多个field的,可以从图看到,一次性删除了name和color属性。
7、当不存在时设置
指令HSETNX用于在Map的Key不存在时执行HSET操作,如果存在,则不作任何操作。这个指令可以看做HSET NOT EXISTS的缩写。
演示如下:
可以看到当Map的Key存在时,这条指令并没有对Value其进行覆盖。在Java中与之相对应的方法是putIfAbsent。与之对应的Java代码如下:
但有区别,上述代码是分成了两步操作 1) 判断Key是否存在 2) 不存在进行put操作。而HSETNX是一个原子操作指令。
8、HINCRBY指令
看到这个指令会想起String类型的INCR、DECR等指令。的确,这个指令与INCRBY指令操作完全一致,并且都会在对应的Key不存在时执行SET操作。演示如下:
上图中的Key1并不存在,可以看到HINCRBY指令在Map以及Map的Key都不存在的情况下,会先创建Map,然后HSET操作。这个指令只对Value为字符串类型的整数有效,如下图:
Redis的Java操作
测试代码如下,略长。
总结:
Redis的Map类型可以将其当做是Java中的Map,但又有所不同,可以将对象序列化成字符串进行存储。既然转换为字符串,就与对象原本的类型无关了。所以与Java中的Map第一个区别是Java的Map的Value只能为一种类型,而Redis的Map的Value可以多种类型(字符串形式)。第二个区别是遍历Redis中Map的Key,Value或者Key-Value会被转换为List或Set进行操作,HKEYS是转为Set,HVAL是转为List,HGETALL是转为List。为什么HKEYS是Set,而HVAL是List,是因为Map的特性使然,这一点与Java的Map保持了一致,分别对应keySet(),values(),entrySet()方法。但这三个方法又与Redis的指令有所区别,这儿不在详细讲解区别。第三个区别Redis提供了一些Java中Map没有的操作,例如HINCRBY指令。同时Java
Map也有一些操作Redis没有,例如clear(), getOrDefault().
参考资料
《Redis入门指南》
可以将Map当做Java中的HashMap,这样便于快速理解。既然将其看做Map,那Redis的这个Map肯定与Java中的Map有相似之处,如下图:
可以看到Key对应的Value是一个Map,而Map内部又有Key-Value键值对。内部的Key也是不能重复的,Value的值也是会被覆盖的。
1、设值/取值(put/get)
使用HSET与HGET获取Map的值,当然,与String类型一样,Map也能一次性获取多个或者设置多个值(HMSET/HMGET)。但设置多个值时,Key-Value一定要成对出现。否则当前指令会执行失败,原Map不会有任何改变。
可以看到取出来的值是String类型的。同时Key的值没有重复,且Value的值会被覆盖,如果获取的Key对应Map的key不存在,则会返回nil。
还有一点值得注意的是HSET,如果是插入新的Key-Value返回的是1,如果是修改旧的Value,返回是0.
2、获取Map内部的Key-Value对数(Map的size())。
使用HLEN指令可以获取指定的Map的Key-Value对数。同时,这个指令与STRLEN和LLEN指令一致,会在Key不存在时返回0.
3、获取Map的所有Key或者所有Value
指令HKEYS获取指定Map的所有Key,与Java中Map的KeySet一致。
指令KVALS获取指定Map的所有Value,在Java的Map中,对应values(),但有所不同。
示例如下:
4、获取Map的所有Key-Value。
可以使用指令HGETALL获取Map的所有Key-Value,与之对应的方法是Java中Map的entrySet方法。演示如下
单行为Key,双行为Value,获取不存在的Redis的Key,返回empty list,可以从提示信息看到,这个指令是将Map遍历然后转换成List类型呈现。
5、判断Map中的Key是否存在(containsKey)
指令用于HEXISTS用于判断Map中对应的Key是否存在。演示如下
我的Redis中是没有Key1这个键存在的,可以看到使用HEXISTS返回0表示Map中没有这个键,但也有可能是这个Map根本不存在。
6、删除Map中的Key(remove)
使用HDEL指令删除Map中的Key,格式HDEL map field。演示如下:
这个指令是可以跟多个field的,可以从图看到,一次性删除了name和color属性。
7、当不存在时设置
指令HSETNX用于在Map的Key不存在时执行HSET操作,如果存在,则不作任何操作。这个指令可以看做HSET NOT EXISTS的缩写。
演示如下:
可以看到当Map的Key存在时,这条指令并没有对Value其进行覆盖。在Java中与之相对应的方法是putIfAbsent。与之对应的Java代码如下:
default V putIfAbsent(K key, V value) { V v = get(key); if (v == null) { v = put(key, value); } return v; }
但有区别,上述代码是分成了两步操作 1) 判断Key是否存在 2) 不存在进行put操作。而HSETNX是一个原子操作指令。
8、HINCRBY指令
看到这个指令会想起String类型的INCR、DECR等指令。的确,这个指令与INCRBY指令操作完全一致,并且都会在对应的Key不存在时执行SET操作。演示如下:
上图中的Key1并不存在,可以看到HINCRBY指令在Map以及Map的Key都不存在的情况下,会先创建Map,然后HSET操作。这个指令只对Value为字符串类型的整数有效,如下图:
Redis的Java操作
测试代码如下,略长。
package org.yamikaze.redis.test; import org.junit.After; import org.junit.Before; import org.junit.Test; import redis.clients.jedis.Jedis; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import static org.junit.Assert.*; /** * 使用Java代码连接测试Redis的Map类型 * @author yamikaze */ public class MapTest { private Jedis client; private static final String KEY = "mapKey"; private String key1 = "key1"; private String value1 = "value1"; private String key2 = "key2"; private String value2 = "value2"; private Map<String, String> map; @Before public void setUp() { client = MyJedisFactory.defaultJedis(); map = new HashMap<String, String>(4); map.put(key1, value1); map.put(key2, value2); } /** * 测试普通的HSET与HGET */ @Test public void testMapPutAndGet() { Long result = client.hset(KEY, key1, value1); assertTrue(result.equals(1L)); String value = client.hget(KEY, key1); assertEquals(value1, value); } /** * 测试HMSET与HMSET */ @Test public void testMapMPutAndMGet() { String result = client.hmset(KEY, map); assertTrue("OK".equals(result)); List<String> list = client.hmget(KEY, key1, key2); assertNotNull(list); assertTrue(list.size() == 2); } /** * 测试HLEN */ @Test public void testMapHLen() { String result = client.hmset(KEY, map); assertTrue("OK".equals(result)); Long size = client.hlen(KEY); assertEquals(size.intValue(), map.size()); } /** * 测试HKEYS */ @Test public void testMapHKeys() { String result = client.hmset(KEY, map); assertTrue("OK".equals(result)); Set<String> redisKeys = client.hkeys(KEY); Set<String> keys = map.keySet(); assertEquals(redisKeys.size(), keys.size()); /** * 两个Set的元素都应该一致. * 不能使用将下面的代码中Keys与RedisKeys互换位置。 * 因为HashMap返回的Set是内部KeySet,不支持add操作。 * 你可以认为HashMap返回的Set是一个可读副本 */ for(String key : keys ) { assertFalse(redisKeys.add(key)); } } /** * 测试HEXISTS */ @Test public void testMapHExists() { String result = client.hmset(KEY, map); assertTrue("OK".equals(result)); assertTrue(client.hexists(KEY, key1)); assertTrue(client.hexists(KEY, key2)); assertFalse(client.hexists(KEY, "abc")); } /** * 测试HDEL */ @Test public void testMapHDel() { String result = client.hmset(KEY, map); assertTrue("OK".equals(result)); Long delResult = client.hdel(KEY, key1, key2); assertTrue(delResult.intValue() == map.size()); assertTrue(client.hlen(KEY).intValue() == 0); } /** * 测试HSETNX */ @Test public void testMapHSetNX() { String result = client.hmset(KEY, map); assertTrue("OK".equals(result)); Long result1 = client.hsetnx(KEY, key1, "123"); String value = client.hget(KEY, key1); assertEquals(value1, value); assertTrue(result1 == 0); Long result2 = client.hsetnx(KEY, "abc", value2); assertTrue(result2 == 1); String value3 = client.hget(KEY, "abc"); assertEquals(value3, value2); } /** * 测试HGETALL */ @Test public void testMapGetAll() { String result = client.hmset(KEY, map); assertTrue("OK".equals(result)); Map<String, String> redisMap = client.hgetAll(KEY); assertNotNull(redisMap); assertEquals(redisMap.size(), map.size()); Set<Map.Entry<String, String>> entrySet = map.entrySet(); for(Map.Entry<String, String> entry : entrySet) { String key = entry.getKey(); String val = entry.getValue(); String redisValue = redisMap.get(key); assertTrue(redisMap.containsKey(key)); assertEquals(val, redisValue); } } /** * 测试HINCRBY */ @Test public void testMapHIncrBy() { String result = client.hmset(KEY, map); assertTrue("OK".equals(result)); Long result1 = client.hincrBy(KEY, "abc", 2); assertEquals(result1.intValue(), 2); } /** * HVALS指令略 */ @After public void tearDown() { if(client != null) { client.del(KEY); } } }
总结:
Redis的Map类型可以将其当做是Java中的Map,但又有所不同,可以将对象序列化成字符串进行存储。既然转换为字符串,就与对象原本的类型无关了。所以与Java中的Map第一个区别是Java的Map的Value只能为一种类型,而Redis的Map的Value可以多种类型(字符串形式)。第二个区别是遍历Redis中Map的Key,Value或者Key-Value会被转换为List或Set进行操作,HKEYS是转为Set,HVAL是转为List,HGETALL是转为List。为什么HKEYS是Set,而HVAL是List,是因为Map的特性使然,这一点与Java的Map保持了一致,分别对应keySet(),values(),entrySet()方法。但这三个方法又与Redis的指令有所区别,这儿不在详细讲解区别。第三个区别Redis提供了一些Java中Map没有的操作,例如HINCRBY指令。同时Java
Map也有一些操作Redis没有,例如clear(), getOrDefault().
参考资料
《Redis入门指南》
相关文章推荐
- Redis 学习笔记(三)之散列类型命令
- redis学习笔记4--散列类型
- Redis 学习笔记(三)之散列类型命令
- redis学习笔记5--列表类型
- redis学习笔记之list类型
- Redis学习笔记(九)--Redis常用五大数据类型
- Redis 学习笔记(二)之字符串类型命令
- Redis字符类型和散列类型学习
- Redis 学习笔记--数据类型常用命令
- Redis 学习笔记(五)之列表类型
- Redis学习笔记---数据类型二(set、sortedset)
- redis学习笔记二之数据类型
- Redis学习笔记---数据类型一(string、list、hash)
- Redis学习笔记2--Redis数据类型及相关命令
- 二 redis学习笔记之数据类型
- 二 redis学习笔记之数据类型
- Redis系列学习笔记3 散列
- 关于Redis五种类型对象的学习笔记
- Redis学习笔记之入门基础知识——五种数据类型
- redis学习笔记3,String类型