引入

在学习操作系统时,我们知道,为了缓解CPU和磁盘的读取速度不匹配的问题,引入了内存的概念。

然而,在一个Spring Boot项目中,假如仅使用mysql作为持久层数据库,数据从磁盘取出直接应用,则相当于放弃了在内存这一层面的数据管理,进而导致类似的读取速度不匹配的问题。为了解决这个问题,可以引入Redis实现缓存。

Spring Data Redis是Spring Data项目的一个子项目,通过它我们在Spring应用中只需要简单的配置和操作就能访问Redis。对于存储的交互它提供了抽象,让你无需关心对应的底层实现。

Redis Insight: 可视化管理工具

RedisInsight是唯一能支持Redis增强功能的工具。

下载地址:https://redis.com/redis-enterprise/redis-insight/

Spring Data Redis的使用步骤

当SpringBoot结合Redis来作为缓存使用时,最简单的方式就是使用Spring Cache了,使用它我们无需知道Spring中对Redis的各种操作,仅仅通过它提供的@Cacheable@CachePut@CacheEvict 、@EnableCaching等注解就可以实现缓存功能。

1.在pom.xml中添加项目依赖;

1
2
3
4
5
<!--redis依赖配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2.修改配置文件application.yml,添加Redis的连接配置;

1
2
3
4
5
6
7
spring:
redis:
host: localhost # Redis服务器地址
database: 0 # Redis数据库索引(默认为0)
port: 6379 # Redis服务器连接端口
password: # Redis服务器连接密码(默认为空)
timeout: 1000ms # 连接超时时间

3.在启动类上添加@EnableCaching注解启动缓存功能;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* SpringBoot配置类
*
* @author AaronWu
*/
@SpringBootApplication
@MapperScan(basePackages= {"com.qdu.mapper"})
@EnableCaching
public class SsmApplication {

public static void main(String[] args) {
SpringApplication.run(SsmApplication.class, args);
}

}

4.在Service层的实现类中,需要对数据进行读、写,或删除操作的方法上使用相关注解实现缓存。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Override
//读
@Cacheable(value = "tag", key = "#tag.TId", unless = "#result==null")
public Tag getOneTagByName(String tName) {
return tagMapper.getOneByName(tName);
}
//写
@Override
@CachePut(value = "tag",key = "#tag.TId")
public int insertTag(Tag tag) {
try {
tagMapper.insert(tag);
}catch (Exception e){
return ReturnValues.FAILED;
}
return ReturnValues.SUCCESS;
}
//删
@Override
@CacheEvict(value = "tag",key = "#tag.TId")
public int deleteTag(Tag tag) {
tagMapper.delete(tag.getTId());
return ReturnValues.SUCCESS;
}

Spring Data Redis的常用注解

@EnableCaching 开启缓存功能,一般放在启动类上。
@Cacheable 使用该注解的方法当缓存存在时,会从缓存中获取数据而不执行方法,当缓存不存在时,会执行方法并把返回结果存入缓存中。一般使用在查询方法上,可以设置如下属性: value:缓存名称(必填),指定缓存的命名空间; key:用于设置在命名空间中的缓存key值,可以使用SpEL表达式定义; unless:条件符合则不缓存; condition:条件符合则缓存。
@CachePut 使用该注解的方法每次执行时都会把返回结果存入缓存中。一般使用在新增方法上,可以设置如下属性: value:缓存名称(必填),指定缓存的命名空间; key:用于设置在命名空间中的缓存key值,可以使用SpEL表达式定义; unless:条件符合则不缓存; condition:条件符合则缓存
@CacheEvict 使用该注解的方法执行时会清空指定的缓存。一般使用在更新或删除方法上,可以设置如下属性: value:缓存名称(必填),指定缓存的命名空间; key:用于设置在命名空间中的缓存key值,可以使用SpEL表达式定义; condition:条件符合则清空缓存

使用Redis连接池

Jedis vs Lettuce

Jedis在实现上是直连Redis服务,多线程环境下非线程安全,除非使用连接池,为每个 RedisConnection 实例增加物理连接。

Lettuce是一种可伸缩,线程安全,完全非阻塞的Redis客户端,多个线程可以共享一个RedisConnection,它利用Netty NIO框架来高效地管理多个连接,从而提供了异步和同步数据访问方式,用于构建非阻塞的反应性应用程序。

SpringBoot 1.5.x版本Redis客户端默认是Jedis实现的,SpringBoot 2.x版本中默认客户端是用Lettuce实现的。

连接池能够有效地管理 Redis 连接,避免频繁地创建和销毁连接,减少资源的浪费。连接池会维护一定数量的连接,当需要连接时,从连接池中获取可用连接,使用完毕后归还到连接池中,而不是每次都重新创建连接。这样可以降低系统的开销,提高资源的利用率。

修改配置以实现连接池

1
2
3
4
5
6
7
8
spring:
redis:
lettuce:
pool:
max-active: 8 # 连接池最大连接数
max-idle: 8 # 连接池最大空闲连接数
min-idle: 0 # 连接池最小空闲连接数
max-wait: -1ms # 连接池最大阻塞等待时间,负值表示没有限制