SpringBoot快速操作Redis数据

在SpringBoot框架中提供了spring-boot-starter-data-redis的依赖组件进行操作Redis服务,当引入了该组件之后,只需要配置Redis的配置即可进行链接Redis服务并且进行操作Redis服务数据。

针对于不同的版本有了不同的底层客户端的支持的底层客户端框架是不同的:目前常见的客户端为Jedis和Lettuce。

低版本SpringBoot支持的Jedis

Jedis是很常用的Redis的Java 实现的客户端。支持基本的数据类型如:String、Hash、List、Set、Sorted Set。

特点:使用阻塞的 I/O,方法调用同步,程序流需要等到 socket 处理完 I/O 才能执行,不支持异步操作。Jedis 客户端实例不是线程安全的,需要通过连接池来使用 Jedis。

高版本版本SpringBoot支持的Lettuce

Lettuce客户端主要用于线程安全同步,异步和响应使用,支持集群,Sentinel,管道和编码器。

基于 Netty 框架的事件驱动的通信层,其方法调用是异步的。Lettuce 的 API 是线程安全的,所以可以操作单个 Lettuce 连接来完成各种操作。

spring-data-redis针对jedis提供了如下功能:

Spring Boot 的 spring-boot-starter-data-redis 为 Redis 的相关操作提供了一个高度封装的 RedisTemplate 类,而且对每种类型的数据结构都进行了归类,实现连接池自动管理,提供了一个高度封装的“RedisTemplate”类。 针对jedis/Lettuce客户端中大量api进行了归类封装,将同一类型操作封装为operation接口。

通用的接口类型工厂方法

提供了对key的“bound”(绑定)便捷化操作API,可以通过bound封装指定的key,然后进行一系列的操作而无须“显式”的再次指定Key,即BoundKeyOperations:

  • ValueOperations - BoundValueOperations:String类型的简单K-V操作
  • SetOperations - BoundSetOperations:set类型数据操作
  • ZSetOperations - BoundListOperations:zset类型数据操作
  • HashOperations - BoundSetOperations:针对map类型的数据操作
  • ListOperations - BoundHashOperations:针对list类型的数据操作

序列化/反序列化的扩展机制

针对数据的“序列化/反序列化”,提供了多种可选择策略(RedisSerializer)

JdkSerializationRedisSerializer

POJO对象的存取场景,使用JDK本身序列化机制,将pojo类通过ObjectInputStream/ObjectOutputStream进行序列化操作,最终redis-server中将存储字节序列。是目前最常用的序列化策略。

StringRedisSerializer

Key或者value为字符串的场景,根据指定的charset对数据的字节序列编码成string,是“new String(bytes, charset)”和“string.getBytes(charset)”的直接封装。是最轻量级和高效的策略。

JacksonJsonRedisSerializer

jackson-json工具提供了javabean与json之间的转换能力,可以将pojo实例序列化成json格式存储在redis中,也可以将json格式的数据转换成pojo实例。因为jackson工具在序列化和反序列化时,需要明确指定Class类型,因此此策略封装起来稍微复杂。【需要jackson-mapper-asl工具支持】

Jackson2JsonRedisSerializer

使用Jackson库将对象序列化为JSON字符串。优点是速度快,序列化后的字符串短小精悍,不需要实现Serializable接口。但缺点也非常致命,那就是此类的构造函数中有一个类型参数,必须提供要序列化对象的类型信息(.class对象)。 通过查看源代码,发现其只在反序列化过程中用到了类型信息。

OxmSerializer

提供了将javabean与xml之间的转换能力,目前可用的三方支持包括jaxb,apache-xmlbeans;redis存储的数据将是xml工具。不过使用此策略,编程将会有些难度,而且效率最低;不建议使用。【需要spring-oxm模块的支持】

扩展第三方序列化工具

当然了除了以上这几种基本的序列化器之外您还可以进行自定义一些更加优秀、速度更块的序列化方式,例如:FastJsonRedisSerializer和KryoRedisSerializer、FSTRedisSerializer等。

RedisSerializer接口

RedisSerializer 基础接口定义了将对象转换为字节数组(二进制数据)的序列化和反序列化方法。建议将实现设计为在序列化和反序列化端处理空对象/空字节数组。注意,Redis 不接受空键或空值,但可以返回 null(对于不存在的键)。

RedisSerializer 接口方法定义

序列化

序列化方法定义如下:

  1. byte[] serialize(T t)

该方法将给定对象 t 序列化为二进制数据,及字节数组。注意:对象 t 和返回值可以为 null。

反序列化

反序列化方法定义如下:

  1. T deserialize(byte[] bytes)

该方法将从给定的二进制数据(字节数组)反序列化为一个对象。注意:bytes 字节数组和返回值 T 均可以为 null。

注意:如果上面的 serialize() 和 deserialize() 方法在执行时报错,将抛出org.springframework.data.redis.serializer.SerializationException 异常。

引入spring-boot-starter-data-redis组件

springboot 与redis的整合,pom文件,依赖如下:

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-data-redis</artifactId>
  4. </dependency>

配置对应的application.properties文件

针对于配置我们按照jedis的配置为基础案例,如下所示。

  1. # Redis数据库索引(默认为0)
  2. spring.redis.database=0
  3. # Redis服务器地址
  4. spring.redis.host=127.0.0.1
  5. # Redis服务器连接端口
  6. spring.redis.port=6379
  7. # Redis服务器连接密码(默认为空)
  8. spring.redis.password=
  9. # 连接池最大连接数(使用负值表示没有限制)
  10. spring.redis.pool.max-active=8
  11. # 连接池最大阻塞等待时间(使用负值表示没有限制)
  12. spring.redis.pool.max-wait=-1
  13. # 连接池中的最大空闲连接
  14. spring.redis.pool.max-idle=8
  15. # 连接池中的最小空闲连接
  16. spring.redis.pool.min-idle=0
  17. # 连接超时时间(毫秒)
  18. spring.redis.timeout=0

对应的SpringBoot-Redis的核心配置类

此处需要定义RedisTemplate对象的配置类,其中需要配置对应的RedisConnectionFactory对象类以及对应类型的序列化和反序列化组件起。如下所示

定义对应的redisTemplate对象类

默认是JDK的序列化策略,这里配置redisTemplate采用的是Jackson2JsonRedisSerializer的序列化策略,参数为redisConnectionFactory。

  1. @Bean
  2. public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
  3. //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
  4. Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
  5. ObjectMapper om = new ObjectMapper();
  6. // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
  7. om.setVisibility(PropertyAccessor.ALL,JsonAutoDetect.Visibility.ANY);
  8. // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会抛出异常
  9. om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
  10. jackson2JsonRedisSerializer.setObjectMapper(om);
  11. RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
  12. // 配置连接工厂
  13. redisTemplate.setConnectionFactory(redisConnectionFactory);
  14. //使用StringRedisSerializer来序列化和反序列化redis的key值
  15. //redisTemplate.setKeySerializer(new StringRedisSerializer());
  16. redisTemplate.setKeySerializer(jackson2JsonRedisSerializer);
  17. // 值采用json序列化
  18. redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
  19. redisTemplate.setHashKeySerializer(jackson2JsonRedisSerializer);
  20. redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
  21. redisTemplate.afterPropertiesSet();
  22. return redisTemplate;
  23. }

定义对应的StringRedisTemplate对象类

但是对于 string 类型的数据,Spring Boot 还专门提供了 StringRedisTemplate 类,而且官方也建议使用该类来操作 String 类型的数据。stringRedisTemplate默认采用的是String的序列化策略。

  1. @Bean
  2. public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory){
  3. StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
  4. stringRedisTemplate.setConnectionFactory(redisConnectionFactory);
  5. return stringRedisTemplate;
  6. }
StringRedisTemplate和 RedisTemplate 又有啥区别呢?
  • RedisTemplate 是一个泛型类,而 StringRedisTemplate 不是,后者只能对键和值都为 String 类型的数据进行操作,而前者则可以操作任何类型。

  • 两者的数据是不共通的,StringRedisTemplate 只能管理 StringRedisTemplate 里面的数据,RedisTemplate 只能管理 RedisTemplate 中 的数据。

定义组合序列化方式

key采用String序列化,value使用jackson序列化,如下代码所示。

  1. @Bean
  2. public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
  3. RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
  4. template.setConnectionFactory(factory);
  5. Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
  6. ObjectMapper om = new ObjectMapper();
  7. om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
  8. om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
  9. jackson2JsonRedisSerializer.setObjectMapper(om);
  10. StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
  11. // key采用String的序列化方式
  12. template.setKeySerializer(stringRedisSerializer);
  13. // hash的key也采用String的序列化方式
  14. template.setHashKeySerializer(stringRedisSerializer);
  15. // value序列化方式采用jackson
  16. template.setValueSerializer(jackson2JsonRedisSerializer);
  17. // hash的value序列化方式采用jackson
  18. template.setHashValueSerializer(jackson2JsonRedisSerializer);
  19. template.afterPropertiesSet();
  20. return template;
  21. }

定义RedisTemplate的脚手架

将形成一个快速操作数据的工具类,将各种类型的操作类进行封装处理控制。

  • HashOperations:对hash类型的数据操作
  • ValueOperations:对redis字符串类型数据操作
  • ListOperations:对链表类型的数据操作
  • SetOperations:对无序集合类型的数据操作
  • ZSetOperations:对有序集合类型的数据操作

将以上各种类型的类直接进行暴漏,减少调用链路的路径长度。

  1. /**
  2. * 对hash类型的数据操作
  3. * @param redisTemplate
  4. * @return
  5. */
  6. @Bean
  7. public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
  8. return redisTemplate.opsForHash();
  9. }
  10. /**
  11. * 对redis字符串类型数据操作
  12. * @param redisTemplate
  13. * @return
  14. */
  15. @Bean
  16. public ValueOperations<String, Object> valueOperations(RedisTemplate<String, Object> redisTemplate) {
  17. return redisTemplate.opsForValue();
  18. }
  19. /**
  20. * 对链表类型的数据操作
  21. * @param redisTemplate
  22. * @return
  23. */
  24. @Bean
  25. public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
  26. return redisTemplate.opsForList();
  27. }
  28. /**
  29. * 对无序集合类型的数据操作
  30. * @param redisTemplate
  31. * @return
  32. */
  33. @Bean
  34. public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
  35. return redisTemplate.opsForSet();
  36. }
  37. /**
  38. * 对有序集合类型的数据操作
  39. * @param redisTemplate
  40. * @return
  41. */
  42. @Bean
  43. public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
  44. return redisTemplate.opsForZSet();
  45. }

定义基础层的操作处理定义RedisSupport

除了以上这几种类型的操作之外,还有一些基础相关的核心操作类,包含重命名,转移以及情况整个库的操作、设置TTL生命周期等。

  1. @Component
  2. public class RedisSupport {
  3. @Autowired
  4. private RedisTemplate<String, String> redisTemplate;
  5. /**
  6. * 默认过期时长,单位:秒
  7. */
  8. public static final long DEFAULT_EXPIRE = 60 * 60 * 24;
  9. /**
  10. * 不设置过期时长
  11. */
  12. public static final long NOT_EXPIRE = -1;
  13. public boolean existsKey(String key) {
  14. return redisTemplate.hasKey(key);
  15. }
  16. /**
  17. * 重名名key,如果newKey已经存在,则newKey的原值被覆盖
  18. *
  19. * @param oldKey
  20. * @param newKey
  21. */
  22. public void renameKey(String oldKey, String newKey) {
  23. redisTemplate.rename(oldKey, newKey);
  24. }
  25. /**
  26. * newKey不存在时才重命名
  27. *
  28. * @param oldKey
  29. * @param newKey
  30. * @return 修改成功返回true
  31. */
  32. public boolean renameKeyNotExist(String oldKey, String newKey) {
  33. return redisTemplate.renameIfAbsent(oldKey, newKey);
  34. }
  35. /**
  36. * 删除key
  37. *
  38. * @param key
  39. */
  40. public void deleteKey(String key) {
  41. redisTemplate.delete(key);
  42. }
  43. /**
  44. * 删除多个key
  45. *
  46. * @param keys
  47. */
  48. public void deleteKey(String... keys) {
  49. Set<String> kSet = Stream.of(keys).map(k -> k).collect(Collectors.toSet());
  50. redisTemplate.delete(kSet);
  51. }
  52. /**
  53. * 删除Key的集合
  54. *
  55. * @param keys
  56. */
  57. public void deleteKey(Collection<String> keys) {
  58. Set<String> kSet = keys.stream().map(k -> k).collect(Collectors.toSet());
  59. redisTemplate.delete(kSet);
  60. }
  61. /**
  62. * 设置key的生命周期
  63. *
  64. * @param key
  65. * @param time
  66. * @param timeUnit
  67. */
  68. public void expireKey(String key, long time, TimeUnit timeUnit) {
  69. redisTemplate.expire(key, time, timeUnit);
  70. }
  71. /**
  72. * 指定key在指定的日期过期
  73. *
  74. * @param key
  75. * @param date
  76. */
  77. public void expireKeyAt(String key, Date date) {
  78. redisTemplate.expireAt(key, date);
  79. }
  80. /**
  81. * 查询key的生命周期
  82. *
  83. * @param key
  84. * @param timeUnit
  85. * @return
  86. */
  87. public long getKeyExpire(String key, TimeUnit timeUnit) {
  88. return redisTemplate.getExpire(key, timeUnit);
  89. }
  90. /**
  91. * 将key设置为永久有效
  92. *
  93. * @param key
  94. */
  95. public void persistKey(String key) {
  96. redisTemplate.persist(key);
  97. }
  98. }

至此整体对应的RedisTemplate对象的封装和扩展就到这里,可以把代码介入到你的项目里面,非常方便的进行操作Redis了,是不是很OK呢?

【SpringBoot实战专题】「开发实战系列」从零开始教你舒服的使用RedisTemplate操作Redis数据的更多相关文章

  1. 🏆【Java技术专区】「开发实战专题」Lombok插件开发实践必知必会操作!

    前言 在目前众多编程语言中,Java 语言的表现还是抢眼,不论是企业级服务端开发,还是 Andorid 客户端开发,都是作为开发语言的首选,甚至在大数据开发领域,Java 语言也能占有一席之地,如Ha ...

  2. 【分布式技术专题】「OSS中间件系列」Minio的文件服务的存储模型及整合Java客户端访问的实战指南

    Minio的元数据 数据存储 MinIO对象存储系统没有元数据数据库,所有的操作都是对象级别的粒度的,这种做法的优势是: 个别对象的失效,不会溢出为更大级别的系统失效. 便于实现"强一致性& ...

  3. 【SpringCloud技术专题】「Gateway网关系列」(3)微服务网关服务的Gateway全流程开发实践指南(2.2.X)

    开发指南须知 本次实践主要在版本:2.2.0.BUILD-SNAPSHOT上进行构建,这个项目提供了构建在Spring生态系统之上API网关. Spring Cloud Gateway的介绍 Spri ...

  4. 【微信小程序】开发实战 之 「开发框架MINA构成」

    小程序开发框架的目标是通过尽可能简单.高效的方式让开发者可以在微信中开发具有原生 APP 体验的服务. 微信团队为小程序提供的框架命名为MINA.MINA框架通过封装微信客户端提供的文件系统.网络通信 ...

  5. 2、SpringBoot接口Http协议开发实战8节课(1-6)

    1.SpringBoot2.xHTTP请求配置讲解 简介:SpringBoot2.xHTTP请求注解讲解和简化注解配置技巧 1.@RestController and @RequestMapping是 ...

  6. 2、SpringBoot接口Http协议开发实战8节课(7-8)

    7.SpringBoot2.x文件上传实战 简介:讲解HTML页面文件上传和后端处理实战 1.讲解springboot文件上传 MultipartFile file,源自SpringMVC 1)静态页 ...

  7. 小D课堂 - 零基础入门SpringBoot2.X到实战_第2节 SpringBoot接口Http协议开发实战_6、SpringBoot2.xHTTP请求配置讲解

    1.SpringBoot2.xHTTP请求配置讲解 简介:SpringBoot2.xHTTP请求注解讲解和简化注解配置技巧 1.@RestController and @RequestMapping是 ...

  8. 【Java技术专题】「性能优化系列」针对Java对象压缩及序列化技术的探索之路

    序列化和反序列化 序列化就是指把对象转换为字节码: 对象传递和保存时,保证对象的完整性和可传递性.把对象转换为有字节码,以便在网络上传输或保存在本地文件中: 反序列化就是指把字节码恢复为对象: 根据字 ...

  9. 【Netty技术专题】「原理分析系列」Netty强大特性之ByteBuf零拷贝技术原理分析

    零拷贝Zero-Copy 我们先来看下它的定义: "Zero-copy" describes computer operations in which the CPU does n ...

  10. ☕【Java深层系列】「并发编程系列」深入分析和研究MappedByteBuffer的实现原理和开发指南

    前言介绍 在Java编程语言中,操作文件IO的时候,通常采用BufferedReader,BufferedInputStream等带缓冲的IO类处理大文件,不过java nio中引入了一种基于Mapp ...

随机推荐

  1. [ZJOI2012] 灾难 题解

    爵士好提 Solution 定义\(u\)控制\(v\)当且仅当\(u\)死后\(v\)也会死 把图建出来,从食物向消费者连边 我们不难想到只能先处理食物,再处理消费者,所以先上个拓扑排序 想一想暴力 ...

  2. Map中定义的方法:

    添加.删除.修改操作: Object put(Object key,Object value):将指定key-value添加到(或修改)当前map对象中void putAll(Map m):将m中的所 ...

  3. 7.RabbitMQ系列之topic主题交换器

    topic主题交换器它根据在队列绑定的路由键和路由模式通配符匹配将消息路由到队列. 生产者在消息头中添加路由键并将其发送到主题交换器. 收到消息后,exchange尝试将路由键与绑定到它的所有队列的绑 ...

  4. wpf 手指触摸图片放大缩小 设置放大缩小值

    xaml代码: <Window x:Class="WpfApp1.MainWindow" xmlns="http://schemas.microsoft.com/w ...

  5. iptables入门到精通

    iptables其实不是真正的防火墙,我们可以把它理解成一个客户端代理,用户通过iptables这个代理,将用户的安全设定执行到对应的"安全框架"中,这个"安全框架&qu ...

  6. 一次 Java log4j2 漏洞导致的生产问题

    一.问题 近期生产在提交了微信小程序审核后(后面会讲到),总会出现一些生产告警,而且持续时间较长.我们查看一些工具和系统相关的,发现把我们的 gateway 差不多打死了. 有一些现象. 网关有很多接 ...

  7. 12、求Sn = a + aa + aaa + aaaa + ....其中a为一个数字,一共有n项。a和n由用户键盘输入。

    /* 求Sn = a + aa + aaa + aaaa + ....其中a为一个数字,一共有n项.a和n由用户键盘输入. */ #include <stdio.h> #include & ...

  8. i春秋Do you know upload?

    打开题目是一个文件上传,就先写了一个一句话木马的php文件,直接提交显示文件类型不允许.于是乎将其改为jpeg格式上传,成功了,但是没用,菜刀连不上.再次上传jpg格式的一句话木马(写好php木马后将 ...

  9. matplotlib详细教学

    Matplotlib初相识 认识matplotlib Matplotlib是一个Python 2D绘图库,能够以多种硬拷贝格式和跨平台的交互式环境生成出版物质量的图形,用来绘制各种静态,动态,交互式的 ...

  10. python-封装、继承、多态

    封装 面向对象编程有三大特性:封装.继承.多态,其中最重要的一个特性就是封装.封装指的就是把数据与功能都整合到一起,针对封装到对象或者类中的属性,我们还可以严格控制对它们的访问,分两步实现:隐藏与开放 ...