Redis-04Redis数据结构--哈希hash
文章目录
- 哈希概述
- 客户端操作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相关推荐
- python按hash分组_Python操作redis系列以 哈希(Hash)命令详解(四)
# -*- coding: utf-8 -*- import redis #这个redis不能用,请根据自己的需要修改 r =redis.Redis(host="123.56.74.190& ...
- redis的数据结构||1) 字符串类型2) 哈希类型3) 列表类型4) 集合类型 5) 有序集合类型详解
2. 下载安装 1. 官网:https://redis.io 2. 中文网:http://www.redis.net.cn/ 3. 解压直接可以使用: * re ...
- 将一个键值对添加入一个对象_细品Redis高性能数据结构之hash对象
背景 上一节讲Redis的高性能字符串结构SDS,今天我们来看一下redis的hash对象. Hash对象 简介 redis的hash对象有两种编码(底层实现)方式,字典编码和压缩列表编码.在使用字典 ...
- 【Redis】Redis 哈希 Hash 键值对集合操作 ( 哈希 Hash 键值对集合简介 | 查询操作 | 增加操作 | 修改操作 )
文章目录 一.哈希 Hash 键值对集合 二.查询操作 1.Redis 中查询 Hash 键值对数据 2.查询 Hash 键是否存在 3.查询 Hash 中所有的键 Field 4.查询 Hash 中 ...
- Redis—列表(List)、集合(Set)、哈希(Hash)、有序集合 Zset
Redis-列表List.集合Set.哈希Hash.有序集合 Zset 列表List 单键多值 常用命令 数据结构 Redis 集合(Set) 常用命令 数据结构 Redis 哈希(Hash) 常用命 ...
- Redis数据结构为字典Hash 实践 之 系统数据字典实时触发缓存存储
一.项目用redis-learn,文章参考 Hash底层存储数据的方式确实跟其他数据结构有点不同,其他数据结构几乎都是:Key-Value的存储,而Hash则是:Key – [Field-Value] ...
- Redis数据结构为字典Hash 的 存储、获取、删除等的操作
一.项目用redis-learn,文章参考 Hash底层存储数据的方式确实跟其他数据结构有点不同,其他数据结构几乎都是:Key-Value的存储,而Hash则是:Key – [Field-Value] ...
- Redis学习---(8)Redis 哈希(Hash)
Redis 哈希(Hash) Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象. Redis 中每个 hash 可以存储 232 - 1 键值 ...
- Redis的数据结构及应用场景
2019独角兽企业重金招聘Python工程师标准>>> 一. 谈谈对redis的理解,它的应用场景. Redis是一个key-value存储系统,它支持存储的value类型包括str ...
最新文章
- python画误差棒/带
- 案例九:shell脚本自动创建多个新用户,并设置密码
- Python用selenium获取Cookie并用于登录。
- C++unique函数应用举例
- Hibernate框架(持久化类、缓存、事务管理)
- 2048游戏c语言实验报告,2048游戏语言实验报告.doc
- android继承图,Android图形系统(三)-View绘制流程
- “重命名”用“改名”更好
- MySQL-第十篇多表连接查询
- 控制层SpringMVC和Struts2的区别
- 单片机c语言三角波采样点,单片机课程设计---信号发生器.doc
- Delphi7串口通讯实例(含Spcomm控件)
- 《应用商务统计分析》前言
- 那么如何成为优秀的机械工程师,如何提升自己的实力,有哪些值得注意和学习的呢?
- html js 做一个钟表,html,css,js实现的一个钟表
- 生日快乐程序_时光匆匆,爱你不变——祝星广十七岁生日快乐
- 精神病学专科哪家强?且看最新医院排行榜
- 用vue2写的开发者在线简历导出
- 原来我是水瓶座。。。
- 文内码转换巨匠增强版 官方版
热门文章
- JAVA 游览时间最长,[蓝桥杯][算法训练]景点游览-题解(Java代码)
- 让电脑死机的java代码_小编为你win7系统Java活动脚本出错导致电脑死机的还原方法...
- C++引用作为函数参数
- tf.dtypes.cast
- 递归 算例一(求一个简单嵌套字典的深度)
- 累加出整个范围所有的数最少还需要几个数
- statemodels 笔记: lowess
- 文巾解题 1765. 地图中的最高点
- SVM-支持向量机原理详解与实践之四
- 深度学习100例 | 第53天:用YOLOv5训练自己的数据集(超级详细完整版)