SpringBoot整合Redis

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: SpringBoot整合Redis

       Redis 的常用命令在其他的文章中都已经介绍完了。作为程序员不是要在命令行中使用 Redis,毕竟我们要把 Redis 当做缓存、队列等进行使用时,因此重点还是要在代码中使用。那么,我们就需要去掌握 Redis 相关的 API 的使用方法。


Spring Boot 整合 Redis

       目前主流的 Java 项目都在使用 Spring Boot,那么我们就来在 Spring Boot 中整合 Redis。

       Spring Boot 使用“约定大于配置”的方式逐步的取代了早起通过 XML 进行配置的方式,使得在 Spring Boot 中整合各种库或者依赖都非常的方便。在我们创建 Spring Boot 项目时,选择相关的 Starter 时,在 “NoSQL” 中把 “Spring Data Redis” 项勾选即可。这样就会在 pom 文件中添加相关的依赖,依赖如下:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>

       有了 Redis 的依赖之后,我们就可以在项目中很容易的使用 Redis 的 API 来对 Redis 进行操作了。


Redis API 介绍

       Spring Boot 提供的 Redis API 分为 高阶 API低阶 API高阶 API 是经过一定封装后的 API,而低阶 API 的使用和直接使用 Redis 的命令差不多


       高阶 API 提供了两个类可以供我们使用,分别是 RedisTemplate 和 StringRedisTemplateStringRedisTemplate 继承自 RedisTemplate,StringRedisTemplate 的序列化方式与 RedisTemplate 的序列化的方式不同。具体在使用上的差别不是特别明显,但是数据在存储到 Redis 中的时候,因为序列化方式的不同,会有一定的差别


       低阶 API 其实也是通过 RedisTemplate 或 StringRedisTemplate 来进行获取。低阶 API 的方法和 Redis 的命令差不多


Redis 高阶 API 使用

       先来看看 高阶 API 的使用方法,具体就是 RedisTemplate 和 StringRedisTemplate 两个类的使用。这里不解释具体过多的原理,主要来看看它们 API 的使用,与存储的不同。


       我们来创建一个 TestRedis 的类,并通过注解将其声明为一个 Component,并注入 RedisTemplate 和 StringRedisTemplate 两个类,代码如下。

@ComponentpublicclassTestRedis{
@AutowiredRedisTemplateredisTemplate;
@AutowiredStringRedisTemplatestringRedisTemplate;
publicvoidredis()
    {
    }
}

       我们对 Redis 的所有操作就在这个类中完成。由于我们对项目中没有引入 SpringMVC 等,因此,测试 TestRedis 就直接通过 Spring Boot 的启动类来直接进行调用,启动类的代码如下:

publicstaticvoidmain(String[] args)
{
ConfigurableApplicationContextrun=SpringApplication.run(SpringbootRedisApplication.class, args);
TestRedisbean=run.getBean(TestRedis.class);
bean.redis();
}

       我们接着来测试一下 RedisTemplate 这个类,用它来进行值为字符串的操作,代码如下:

publicvoidtestRedisTemplate()
{
ValueOperationsvalueOperations=redisTemplate.opsForValue();
valueOperations.set("key1", "value1");
valueOperations.set("key2", "哈哈");
System.out.println(valueOperations.get("key1"));
System.out.println(valueOperations.get("key2"));
}

       我们通过 redisTemplate 的 opsForValue 得到一个 ValueOperations 的实例,然后通过它来操作 Redis 的字符串类型。使用它的 set 方法添加了 key1 和 key2 两个键值对。然后,通过它的 get 方法又读取了这两个键对应的值。通过控制台的输出也可以看出,操作是成功的,控制台输出如下:

testRedisTemplate...
value1哈哈

       虽然在代码中操作是没问题的,但是,我们通过 Redis 的客户端来进行查看一下。

127.0.0.1:6379>keys*1) "\xac\xed\x00\x05t\x00\x04key2"2) "\xac\xed\x00\x05t\x00\x04key1"127.0.0.1:6379>get\xac\xed\x00\x05t\x00\x04key2(nil)

       从 Redis 的客户端查看,看到有一些 16 进制的字符,而且也不方便我们进行 get 操作。我们换一种启动 Redis 客户端的方式,在启动 Redis 客户端时,我们来加一个 --raw 的参数,再来查看我们写入的键值对,如下:

[root@node01~]#redis-cli--raw127.0.0.1:6379>keys*��tkey2��tkey1

       可以看到,在键的前面仍然有一些“奇怪”的字符,这些奇怪的字符就是前面看到的那些 16 进制字符。我们来换 StringRedisTemplate 进行相同的操作,代码如下:

publicvoidtestStringRedisTemplate()
{
ValueOperations<String, String>stringStringValueOperations=stringRedisTemplate.opsForValue();
stringStringValueOperations.set("key3", "value3");
stringStringValueOperations.set("key4", "哈哈");
System.out.println(stringStringValueOperations.get("key3"));
System.out.println(stringStringValueOperations.get("key4"));
}

       我们把前面代码注释掉,直接执行我们现在的代码,执行结果如下。

testStringRedisTemplate...
value3哈哈

       我们在到 Redis 中看一下,如下:

127.0.0.1:6379>keys*key4key3127.0.0.1:6379>getkey4哈哈127.0.0.1:6379>getkey3value3

       使用 RedisTemplate 和 StringRedisTemplate 之所以有所差异,是因为 StringRedisTemplate 在对 Key 和 Value 进行序列化时,都使用字符串的方式进行序列化。因此,我们选择 StringRedisTemplate 会方便一些。


Redis 低阶 API 使用

       Redis 的 低阶 API 使用是相对比较麻烦的。同样使用一个例子来进行查看。

publicvoidtestLowApi()
{
RedisConnectionconnection=stringRedisTemplate.getConnectionFactory().getConnection();
connection.set("key5".getBytes(), "value5".getBytes());
connection.set("key6".getBytes(), "哈哈".getBytes());
byte[] bytes=connection.get("key5".getBytes());
System.out.println(newString(bytes));
byte[] bytes1=connection.get("key6".getBytes());
System.out.println(newString(bytes1));
}

       运行代码,输出如下:

testLowApi...
value5哈哈

      同样的,我们到 Redis 的客户端中进行查看,如下:

127.0.0.1:6379>keys*key4key3key6key5127.0.0.1:6379>getkey5value5127.0.0.1:6379>getkey6哈哈

      看着效果也是不错的。不过它的操作过于繁琐,我们还是不考虑使用它。虽然不考虑使用它,但是简单的了解还是要有的。


Redis 高阶 API 操作 Hash

      在 Redis 中,使用哈希结构还是比较常见的。这里给出一个简单的操作哈希结构的代码,我们进行一些简单的操作,代码如下:

publicvoidoptHash()
{
HashOperations<String, Object, Object>stringObjectObjectHashOperations=stringRedisTemplate.opsForHash();
stringObjectObjectHashOperations.put("no1", "name", "zhangsan");
stringObjectObjectHashOperations.put("no1", "age", 22);
System.out.println(stringObjectObjectHashOperations.entries("no1"));
}

      我们来运行一下代码,运行结果如下:

optHash...
Exceptioninthread"main"java.lang.ClassCastException: java.lang.Integercannotbecasttojava.lang.Stringatorg.springframework.data.redis.serializer.StringRedisSerializer.serialize(StringRedisSerializer.java:36)
atorg.springframework.data.redis.core.AbstractOperations.rawHashValue(AbstractOperations.java:185)
atorg.springframework.data.redis.core.DefaultHashOperations.put(DefaultHashOperations.java:189)
atcn.coderup.TestRedis.optHash(TestRedis.java:71)
atcn.coderup.TestRedis.redis(TestRedis.java:32)
atcn.coderup.SpringbootRedisApplication.main(SpringbootRedisApplication.java:16)

       可以看到,运行代码时报错了,原因是在进行转换时发生了异常通过异常抛出的信息可以看出,在 StringRedisSerializer 进行序列化时发生的异常,这个问题是,在我们代码中的第二个 put 方法时传入了一个整型的 22 进去,这里将它改为字符串的 22,修改后的代码如下:

stringObjectObjectHashOperations.put("no1", "age", "22");

       运行修改后的代码,查看输出结果:

optHash...
{name=zhangsan, age=22}

Redis 高阶 API 操作类

       上面的代码虽然完成了对哈希的操作,但是略显繁琐,类似上面的操作我们实际中并不会去逐个的进行 put 操作,更多的应该是将一个实体类存储到 Redis 的哈希类型中。我们通过代码演示一下。


       先定义一个学生类,定义如下:

publicclassStudent{
privateStringname;
privateIntegerage;

       我省去了代码中的 getter 和 setter 方法,大家补全即可。除此而外,需要引入另外一个依赖,用于将对象转为 HashMap 或 HashMap 转换为对象。pom文件中添加的依赖如下:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-json</artifactId></dependency>

       有了上面的依赖以后,我们来接着完成代码,首先将 ObjectMapper 进行注入:

@AutowiredObjectMapperobjectMapper;

       注入 ObjectMapper 后,我们来将实体类写入 Redis 的哈希类型中,代码如下:

publicvoidoptHashForObj()
{
Studentstudent=newStudent();
student.setName("zhangsan");
student.setAge(20);
Jackson2HashMapperjackson2HashMapper=newJackson2HashMapper(objectMapper, false);
HashOperations<String, Object, Object>stringObjectObjectHashOperations=stringRedisTemplate.opsForHash();
// 对象转MapperstringObjectObjectHashOperations.putAll("no2", jackson2HashMapper.toHash(student));
Map<Object, Object>no2=stringObjectObjectHashOperations.entries("no2");
// Map转对象Studentstudent1=objectMapper.convertValue(no2, Student.class);
System.out.println(student1.getName());
System.out.println(student1.getAge());
}

      这样我们的代码看似就完成了,那么我们执行一下,看会输出什么内容,输出如下:

optHashForObj...
Exceptioninthread"main"java.lang.ClassCastException: java.lang.Integercannotbecasttojava.lang.Stringatorg.springframework.data.redis.serializer.StringRedisSerializer.serialize(StringRedisSerializer.java:36)
atorg.springframework.data.redis.core.AbstractOperations.rawHashValue(AbstractOperations.java:185)
atorg.springframework.data.redis.core.DefaultHashOperations.putAll(DefaultHashOperations.java:147)
atcn.coderup.TestRedis.optHashForObj(TestRedis.java:98)
atcn.coderup.TestRedis.redis(TestRedis.java:44)
atcn.coderup.SpringbootRedisApplication.main(SpringbootRedisApplication.java:16)

      可以看出,又抛出了异常,问题同样是因为我们的 Student 类中的 age 属性是 Integer 类型。那么,是不是需要我们将 Integer 类型换成 String 类型呢?如果真的需要将 Integer 类型全部修改为 String 类型的话,那么在实际的项目中就是一场灾难了。那么具体怎么办呢?其实只要修改 Hash 的序列化器,我们在 stringRedisTemplate.opsForHash() 这句代码上增加一句代码,代码如下:

stringRedisTemplate.setHashValueSerializer(newJackson2JsonRedisSerializer<Object>(Object.class));

       再次运行我们的代码,执行结果如下:

optHashForObj...
zhangsan20

       通过 Redis 的客户端来查看我们写入的 Hash 类型的值,也是没有任何问题的。

全局的 Redis 配置

      在上面的代码中,可以通过设置 Hash 类型的序列化器从而方便的使用 putAll() 方法将一个类写入 Redis 中。但是,每次这样的写入都会特别的繁琐,我们定义一个全局的 Redis 的配置类,以后就无需每次使用都进行序列化器的设置了。


       我们添加一个 RedisConfig 类,代码如下:

@ConfigurationpublicclassRedisConfig{
@AutowiredRedisConnectionFactoryredisConnectionFactory;
@BeanpublicStringRedisTemplategetStringRedisTemplate()
    {
StringRedisTemplatestringRedisTemplate=newStringRedisTemplate();
stringRedisTemplate.setConnectionFactory(redisConnectionFactory);
stringRedisTemplate.setHashValueSerializer(newJackson2JsonRedisSerializer<Object>(Object.class));
returnstringRedisTemplate;
    }
}

       有了上面的代码,我们就无需每次都设置序列化器了。为了进行测试,我们删掉前面代码中设置序列化器的代码,然后再执行代码看是否报错,结果是没有问题,不会报错。


总结

       关于在 Spring Boot 中简单整合 Redis 的方法就基本完成了。当然了,这里没有介绍具体如何操作各种数据结构的方法,以及一些 Redis 的实际使用场景,后续再进行介绍吧。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
2月前
|
缓存 NoSQL Java
SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解分布式情况下如何添加分布式锁 【续篇】
这篇文章是关于如何在SpringBoot应用中整合Redis并处理分布式场景下的缓存问题,包括缓存穿透、缓存雪崩和缓存击穿。文章详细讨论了在分布式情况下如何添加分布式锁来解决缓存击穿问题,提供了加锁和解锁的实现过程,并展示了使用JMeter进行压力测试来验证锁机制有效性的方法。
SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解分布式情况下如何添加分布式锁 【续篇】
|
2月前
|
编解码 NoSQL Java
使用Spring Boot + Redis 队列实现视频文件上传及FFmpeg转码的技术分享
【8月更文挑战第30天】在当前的互联网应用中,视频内容的处理与分发已成为不可或缺的一部分。对于视频平台而言,高效、稳定地处理用户上传的视频文件,并对其进行转码以适应不同设备的播放需求,是提升用户体验的关键。本文将围绕使用Spring Boot结合Redis队列技术来实现视频文件上传及FFmpeg转码的过程,分享一系列技术干货。
95 3
|
6天前
|
缓存 NoSQL Java
Springboot自定义注解+aop实现redis自动清除缓存功能
通过上述步骤,我们不仅实现了一个高度灵活的缓存管理机制,还保证了代码的整洁与可维护性。自定义注解与AOP的结合,让缓存清除逻辑与业务逻辑分离,便于未来的扩展和修改。这种设计模式非常适合需要频繁更新缓存的应用场景,大大提高了开发效率和系统的响应速度。
21 2
|
13天前
|
JSON NoSQL Java
redis的java客户端的使用(Jedis、SpringDataRedis、SpringBoot整合redis、redisTemplate序列化及stringRedisTemplate序列化)
这篇文章介绍了在Java中使用Redis客户端的几种方法,包括Jedis、SpringDataRedis和SpringBoot整合Redis的操作。文章详细解释了Jedis的基本使用步骤,Jedis连接池的创建和使用,以及在SpringBoot项目中如何配置和使用RedisTemplate和StringRedisTemplate。此外,还探讨了RedisTemplate序列化的两种实践方案,包括默认的JDK序列化和自定义的JSON序列化,以及StringRedisTemplate的使用,它要求键和值都必须是String类型。
redis的java客户端的使用(Jedis、SpringDataRedis、SpringBoot整合redis、redisTemplate序列化及stringRedisTemplate序列化)
|
7天前
|
存储 NoSQL Java
Spring Boot项目中使用Redis实现接口幂等性的方案
通过上述方法,可以有效地在Spring Boot项目中利用Redis实现接口幂等性,既保证了接口操作的安全性,又提高了系统的可靠性。
9 0
|
2月前
|
缓存 NoSQL Java
SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解、如何添加锁解决缓存击穿问题?分布式情况下如何添加分布式锁
这篇文章介绍了如何在SpringBoot项目中整合Redis,并探讨了缓存穿透、缓存雪崩和缓存击穿的问题以及解决方法。文章还提供了解决缓存击穿问题的加锁示例代码,包括存在问题和问题解决后的版本,并指出了本地锁在分布式情况下的局限性,引出了分布式锁的概念。
SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解、如何添加锁解决缓存击穿问题?分布式情况下如何添加分布式锁
|
2月前
|
NoSQL Java Redis
Redis6入门到实战------ 八、Redis与Spring Boot整合
这篇文章详细介绍了如何在Spring Boot项目中整合Redis,包括在`pom.xml`中添加依赖、配置`application.properties`文件、创建配置类以及编写测试类来验证Redis的连接和基本操作。
Redis6入门到实战------ 八、Redis与Spring Boot整合
|
2月前
|
Web App开发 前端开发 关系型数据库
基于SpringBoot+Vue+Redis+Mybatis的商城购物系统 【系统实现+系统源码+答辩PPT】
这篇文章介绍了一个基于SpringBoot+Vue+Redis+Mybatis技术栈开发的商城购物系统,包括系统功能、页面展示、前后端项目结构和核心代码,以及如何获取系统源码和答辩PPT的方法。
|
2月前
|
缓存 NoSQL Java
惊!Spring Boot遇上Redis,竟开启了一场缓存实战的革命!
【8月更文挑战第29天】在互联网时代,数据的高速读写至关重要。Spring Boot凭借简洁高效的特点广受开发者喜爱,而Redis作为高性能内存数据库,在缓存和消息队列领域表现出色。本文通过电商平台商品推荐系统的实战案例,详细介绍如何在Spring Boot项目中整合Redis,提升系统响应速度和用户体验。
53 0
|
2月前
|
缓存 NoSQL Java
【Azure Redis 缓存】定位Java Spring Boot 使用 Jedis 或 Lettuce 无法连接到 Redis的网络连通性步骤
【Azure Redis 缓存】定位Java Spring Boot 使用 Jedis 或 Lettuce 无法连接到 Redis的网络连通性步骤