文章目录

  • 哈希概述
  • 客户端操作hash
  • Redis hash 结构命令
  • Spring操作reids的hash
    • Step1 修改defaultSerializer
    • Step2 操作hash
  • 注意
  • 代码

哈希概述

Redis 中哈希结构就如同 Java 的 map 一样 , 一个对象里面有许多键值对,它是特别适合存储对象的.

如果内存足够大 ,那么一个 Redis 的 hash 结构可以存储2的32次方-1个键值对 ( 40多亿)。

在 Redis 中, hash 是一个 String 类型的 field 和 value 的映射表,因此我们存储的数据实际在 Redis 内存中都是一个个字符串而己。

假设artisan有 3 个字段 : 编号( id)、名称 (name )、性别( sex),这样就可以使用一个 hash 结构保存它。

在 Redis 中它就是一个这样的结构,其中 artisan代表的是这个 hash 结构在 Redis 内存的 key,通过它就可以找到这个 hash 结构,而 hash 结构由一系列的 field 和 value 组成


客户端操作hash

127.0.0.1:6379> HMSET artisan  id 123 name littleArtisan sex female
OK
127.0.0.1:6379> HGETALL artisan
1) "id"
2) "123"
3) "name"
4) "littleArtisan"
5) "sex"
6) "female"
127.0.0.1:6379> 

Redis hash 结构命令

官网:https://redis.io/commands#hash

命令 说明 备注
hdel key field 1 [ field2 …] 删除 hash 结构中的某个(些)字段 可以进行多个字段的删除
hexists key field 判断 hash 结构中是否存在 field 字段 存在返回 1 ,否则返回0
hgetall key 获取所有 hash 结构中的键值 返回键和值
hincrby key field increment 指定给 hash 结构中的某一字段加上一个整数 要求该字段也是整数字符串
hincrbyfloat key field increment 指定给 hash 结构中的某一字段加上一个浮点数 要求该字段是数字型字符串
hkeys key 返回 hash 中所有的键
hlen key 返问 hash 中键值对的数量
hmget key field1 [field2…] 返回 hash 中指定的键的值,可以是多个 依次返回值
hmset key field1 value1 [field2 value2…] hash 结构设置多个键值对
hset key filed value 在 hash 结构中设置键值对 单个设值
hsetnx key field value 当 hash 结构中不存在对应的键,才设置值
hvals key 获取 hash 结构中所有的值

在 Redis 中的哈希结构和字符串有着比较明显的不同。

  • 首先,命令都是以 h 开头,代表操作的是 hash 结构

  • 其次,大多数命令多了一个层级 field,这是hash 结构的一个内部键,也就是说Redis 需要通过 key 索引到对应的 hash 结构,再通过 field来确定使用 hash 结构的哪个键值对

注意事项:

  • 哈希结构的大小,如果哈希结构是个很大的键值对,那么使用它要十分注意。 尤其是关于 hkeys 、 hgetall 、 hvals 等返回所有哈希结构数据的命令,会造成大量数据的读取。这需要考虑性能和读取数据大小对 JVM 内存的影响 。
  • 对于数字的操作命令 hincrby 而言,要求存储的也是整数型的字符串
  • 对于hincrbyfloat 而言,则要求使用浮点数或者整数,否则命令会失败。
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379>
127.0.0.1:6379>
127.0.0.1:6379> HMSET obj k1 value1 k2 value2 k3 value3
OK
127.0.0.1:6379> HSET obj k4  6
(integer) 1
127.0.0.1:6379> HEXISTS obj k2
(integer) 1
127.0.0.1:6379> HGETALL obj
1) "k1"
2) "value1"
3) "k2"
4) "value2"
5) "k3"
6) "value3"
7) "k4"
8) "6"
127.0.0.1:6379> HINCRBY obj k4 8
(integer) 14
127.0.0.1:6379> HINCRBYFLOAT obj k4 6.2
"20.2"
127.0.0.1:6379> HKEYS obj
1) "k1"
2) "k2"
3) "k3"
4) "k4"
127.0.0.1:6379> HMGET obj k1 k2 k4
1) "value1"
2) "value2"
3) "20.2"
127.0.0.1:6379> HLEN obj
(integer) 4
127.0.0.1:6379> HSETNX obj k2 test
(integer) 0
127.0.0.1:6379> HSETNX obj k5 test
(integer) 1
127.0.0.1:6379> HGETALL obj1) "k1"2) "value1"3) "k2"4) "value2"5) "k3"6) "value3"7) "k4"8) "20.2"9) "k5"
10) "test"
127.0.0.1:6379> HVALS obj
1) "value1"
2) "value2"
3) "value3"
4) "20.2"
5) "test"
127.0.0.1:6379> HDEL obj k5
(integer) 1
127.0.0.1:6379> HGETALL obj
1) "k1"
2) "value1"
3) "k2"
4) "value2"
5) "k3"
6) "value3"
7) "k4"
8) "20.2"
127.0.0.1:6379> HGET obj k4
"20.2"
127.0.0.1:6379> 

Spring操作reids的hash

Step1 修改defaultSerializer

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"xmlns:p="http://www.springframework.org/schema/p"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><context:property-placeholder location="classpath:redis/redis.properties" /><!--2,注意新版本2.3以后,JedisPoolConfig的property name,不是maxActive而是maxTotal,而且没有maxWait属性,建议看一下Jedis源码或百度。 --><!-- redis连接池配置 --><bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"><!--最大空闲数 --><property name="maxIdle" value="${redis.maxIdle}" /><!--连接池的最大数据库连接数 --><property name="maxTotal" value="${redis.maxTotal}" /><!--最大建立连接等待时间 --><property name="maxWaitMillis" value="${redis.maxWaitMillis}" /><!--逐出连接的最小空闲时间 默认1800000毫秒(30分钟) --><property name="minEvictableIdleTimeMillis" value="${redis.minEvictableIdleTimeMillis}" /><!--每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3 --><property name="numTestsPerEvictionRun" value="${redis.numTestsPerEvictionRun}" /><!--逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1 --><property name="timeBetweenEvictionRunsMillis" value="${redis.timeBetweenEvictionRunsMillis}" /><property name="testOnBorrow" value="true"></property><property name="testOnReturn" value="true"></property><property name="testWhileIdle" value="true"></property></bean><!--redis连接工厂 --><bean id="jedisConnectionFactory"class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"destroy-method="destroy"><property name="poolConfig" ref="jedisPoolConfig"></property><!--IP地址 --><property name="hostName" value="${redis.host.ip}"></property><!--端口号 --><property name="port" value="${redis.port}"></property><!--如果Redis设置有密码 --><property name="password" value="${redis.password}" /> <!--客户端超时时间单位是毫秒 --><property name="timeout" value="${redis.timeout}"></property><property name="usePool" value="true" /><!--<property name="database" value="0" /> --></bean><!-- 键值序列化器设置为String 类型 --><bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"/><!-- redis template definition --><bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"p:connection-factory-ref="jedisConnectionFactory"p:keySerializer-ref="stringRedisSerializer"p:defaultSerializer-ref="stringRedisSerializer"p:valueSerializer-ref="stringRedisSerializer"></bean></beans>

在 Redis 中, hash 是一个 String 类型的 field 和 value 的映射表。 Spring 对 Redis 进行了封装,所以有必要对 RedisTemplate 的配置项进行修改。修改defaultSerializer-ref

如果不指定的话就是

否则抛出如下异常

Cannot deserialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException: Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?; nested exception is java.io.EOFException

Step2 操作hash

package com.artisan.redis.baseStructure.hash;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;public class SpringRedisHashDemo {public static void main(String[] args) {ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:spring/spring-redis-hash.xml");RedisTemplate redisTemplate = (RedisTemplate) ctx.getBean("redisTemplate");// 127.0.0.1:6379> HMSET obj k1 value1 k2 value2 k3 value3// OKString key = "obj";Map<String, String> map = new HashMap<String, String>();map.put("k1", "value1");map.put("k2", "value2");map.put("k3", "value3");redisTemplate.opsForHash().putAll(key, map);// 127.0.0.1:6379> HSET obj k4 6// (integer) 1redisTemplate.opsForHash().put(key, "k4", String.valueOf(6));// 127.0.0.1:6379> HEXISTS obj k2// (integer) 1boolean exist = redisTemplate.opsForHash().hasKey(key, "k2");System.out.println(key + " 这个键中是否存在 k2这个field:" + exist);// 127.0.0.1:6379> HGETALL obj// 1) "k1"// 2) "value1"// 3) "k2"// 4) "value2"// 5) "k3"// 6) "value3"// 7) "k4"// 8) "6"Map<String,String> map2 = redisTemplate.opsForHash().entries(key);if (map2 != null) {scanMap(map2);}// 127.0.0.1:6379> HINCRBY obj k4 8// (integer) 14System.out.println(redisTemplate.opsForHash().increment(key, "k4", 8));// 127.0.0.1:6379> HINCRBYFLOAT obj k4 6.2// "20.2"System.out.println(redisTemplate.opsForHash().increment(key, "k4", 6.2));// 127.0.0.1:6379> HKEYS obj// 1) "k1"// 2) "k2"// 3) "k3"// 4) "k4"Set<String> set = redisTemplate.opsForHash().keys(key);for (String str : set) {System.out.println(str);}// 127.0.0.1:6379> HMGET obj k1 k2 k4// 1) "value1"// 2) "value2"// 3) "20.2"List<String> list = new ArrayList<String>();list.add("k1");list.add("k2");list.add("k4");List<String> list2 = redisTemplate.opsForHash().multiGet(key, list);scanList(list2);// 127.0.0.1:6379> HLEN obj// (integer) 4System.out.println(redisTemplate.opsForHash().size(key));// 127.0.0.1:6379> HSETNX obj k2 test// (integer) 0System.out.println(redisTemplate.opsForHash().putIfAbsent(key, "k2", "test"));// 127.0.0.1:6379> HSETNX obj k5 test// (integer) 1System.out.println(redisTemplate.opsForHash().putIfAbsent(key, "k5", "test"));// 127.0.0.1:6379> HGETALL obj// 1) "k1"// 2) "value1"// 3) "k2"// 4) "value2"// 5) "k3"// 6) "value3"// 7) "k4"// 8) "20.2"// 9) "k5"// 10) "test"Map<String, String> map3 = redisTemplate.opsForHash().entries(key);if (map3 != null) {scanMap(map3);}// 127.0.0.1:6379> HVALS obj// 1) "value1"// 2) "value2"// 3) "value3"// 4) "20.2"// 5) "test"List<String> list3 = redisTemplate.opsForHash().values(key);scanList(list3);// 127.0.0.1:6379> HDEL obj k5// (integer) 1redisTemplate.opsForHash().delete(key, "k5");// 127.0.0.1:6379> HGETALL obj// 1) "k1"// 2) "value1"// 3) "k2"// 4) "value2"// 5) "k3"// 6) "value3"// 7) "k4"// 8) "20.2"Map<String, String> map4 = redisTemplate.opsForHash().entries(key);if (map4 != null) {scanMap(map4);}// 127.0.0.1:6379> HGET obj k4// "20.2"System.out.println(redisTemplate.opsForHash().get(key, "k4"));}private static void scanList(List<String> list2) {for (String string : list2) {System.out.println(string);}}private static void scanMap(Map<String, String> map4) {for (Map.Entry<String, String> entry : map4.entrySet()) {System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());}}
}

输出

INFO : org.springframework.context.support.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@73a8dfcc: startup date [Thu Sep 20 19:13:10 CST 2018]; root of context hierarchy
INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [spring/spring-redis-hash.xml]
obj 这个键中是否存在 k2这个field:true
Key = k2, Value = value2
Key = k3, Value = value3
Key = k4, Value = 6
Key = k1, Value = value1
14
20.2
k1
k2
k3
k4
value1
value2
20.2
4
false
true
Key = k2, Value = value2
Key = k5, Value = test
Key = k3, Value = value3
Key = k1, Value = value1
Key = k4, Value = 20.2
value1
value2
value3
20.2
test
Key = k3, Value = value3
Key = k2, Value = value2
Key = k4, Value = 20.2
Key = k1, Value = value1
20.2

  • hmset 命令,在 Java 的 API 中,是使用 map 保存多个键值对。
  • hgetall 命令会返回所有的键值对,并保存到一个 map 对象中,如果 hash 结构很大,那么要考虑它对 JVM 的内存影响。
  • hincrby 和 hincrbyFloat 命令都采用 increment 方法, Spring 会识别它具体使用何种方法。
  • redisTemplate.opsForHash().values(key)方法相当于 hvals 命令,它会返回所有的值,并保存到一个 List 对象中;
  • redisTemplate.opsForHash().keys(key)方法相当于 hkeys命令,它会获取所有的键,保存到一个 Set 对象中 。
  • 在 Spring 中使用 redisTemplate.opsForHash().putAll(key, map )方法相当于执行了hmset 命令,使用了 map ,由于配置了默认的序列化器为字符串,所以它也只会用字符串进行转化,这样才能执行对应的数值加法,如果使用其他序列化器,则后面的命令可能会抛出异常。
  • 在使用大的 hash 结构时,需要考虑返回数据的大小,以避免返回太多的数据,引发JVM内存溢出或者 Redis 的性能问题。

注意

使用 Spring 提供的 RedisTemplate 去展示多个命令可以学习到如何使用 RedisTemplate 操作 Redis 。 实际工作中并不是那么用的,因为每一 个操作会尝试从连接池里获取 一 个新的 Redis 连接,多个命令应该使用SessionCallback 接口进行操作 。


代码

代码托管到了 https://github.com/yangshangwei/redis_learn

Redis-04Redis数据结构--哈希hash相关推荐

  1. python按hash分组_Python操作redis系列以 哈希(Hash)命令详解(四)

    # -*- coding: utf-8 -*- import redis #这个redis不能用,请根据自己的需要修改 r =redis.Redis(host="123.56.74.190& ...

  2. redis的数据结构||1) 字符串类型2) 哈希类型3) 列表类型4) 集合类型 5) 有序集合类型详解

    2. 下载安装     1. 官网:https://redis.io     2. 中文网:http://www.redis.net.cn/     3. 解压直接可以使用:         * re ...

  3. 将一个键值对添加入一个对象_细品Redis高性能数据结构之hash对象

    背景 上一节讲Redis的高性能字符串结构SDS,今天我们来看一下redis的hash对象. Hash对象 简介 redis的hash对象有两种编码(底层实现)方式,字典编码和压缩列表编码.在使用字典 ...

  4. 【Redis】Redis 哈希 Hash 键值对集合操作 ( 哈希 Hash 键值对集合简介 | 查询操作 | 增加操作 | 修改操作 )

    文章目录 一.哈希 Hash 键值对集合 二.查询操作 1.Redis 中查询 Hash 键值对数据 2.查询 Hash 键是否存在 3.查询 Hash 中所有的键 Field 4.查询 Hash 中 ...

  5. Redis—列表(List)、集合(Set)、哈希(Hash)、有序集合 Zset

    Redis-列表List.集合Set.哈希Hash.有序集合 Zset 列表List 单键多值 常用命令 数据结构 Redis 集合(Set) 常用命令 数据结构 Redis 哈希(Hash) 常用命 ...

  6. Redis数据结构为字典Hash 实践 之 系统数据字典实时触发缓存存储

    一.项目用redis-learn,文章参考 Hash底层存储数据的方式确实跟其他数据结构有点不同,其他数据结构几乎都是:Key-Value的存储,而Hash则是:Key – [Field-Value] ...

  7. Redis数据结构为字典Hash 的 存储、获取、删除等的操作

    一.项目用redis-learn,文章参考 Hash底层存储数据的方式确实跟其他数据结构有点不同,其他数据结构几乎都是:Key-Value的存储,而Hash则是:Key – [Field-Value] ...

  8. Redis学习---(8)Redis 哈希(Hash)

    Redis 哈希(Hash) Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象. Redis 中每个 hash 可以存储 232 - 1 键值 ...

  9. Redis的数据结构及应用场景

    2019独角兽企业重金招聘Python工程师标准>>> 一. 谈谈对redis的理解,它的应用场景. Redis是一个key-value存储系统,它支持存储的value类型包括str ...

最新文章

  1. python画误差棒/带
  2. 案例九:shell脚本自动创建多个新用户,并设置密码
  3. Python用selenium获取Cookie并用于登录。
  4. C++unique函数应用举例
  5. Hibernate框架(持久化类、缓存、事务管理)
  6. 2048游戏c语言实验报告,2048游戏语言实验报告.doc
  7. android继承图,Android图形系统(三)-View绘制流程
  8. “重命名”用“改名”更好
  9. MySQL-第十篇多表连接查询
  10. 控制层SpringMVC和Struts2的区别
  11. 单片机c语言三角波采样点,单片机课程设计---信号发生器.doc
  12. Delphi7串口通讯实例(含Spcomm控件)
  13. 《应用商务统计分析》前言
  14. 那么如何成为优秀的机械工程师,如何提升自己的实力,有哪些值得注意和学习的呢?
  15. html js 做一个钟表,html,css,js实现的一个钟表
  16. 生日快乐程序_时光匆匆,爱你不变——祝星广十七岁生日快乐
  17. 精神病学专科哪家强?且看最新医院排行榜
  18. 用vue2写的开发者在线简历导出
  19. 原来我是水瓶座。。。
  20. 文内码转换巨匠增强版 官方版

热门文章

  1. JAVA 游览时间最长,[蓝桥杯][算法训练]景点游览-题解(Java代码)
  2. 让电脑死机的java代码_小编为你win7系统Java活动脚本出错导致电脑死机的还原方法...
  3. C++引用作为函数参数
  4. tf.dtypes.cast
  5. 递归 算例一(求一个简单嵌套字典的深度)
  6. 累加出整个范围所有的数最少还需要几个数
  7. statemodels 笔记: lowess
  8. 文巾解题 1765. 地图中的最高点
  9. SVM-支持向量机原理详解与实践之四
  10. 深度学习100例 | 第53天:用YOLOv5训练自己的数据集(超级详细完整版)