点击上方“后端技术精选”,选择“置顶公众号”

技术文章第一时间送达!

作者:超级小豆丁

http://www.mydlq.club/article/55/

系统环境:

Redis 版本:5.0.7
SpringBoot 版本:2.2.2.RELEASE

参考地址:

Redus 官方网址:https://redis.io/
博文示例项目 Github 地址:https://github.com/my-dlq/blog-example/tree/master/springboot/springboot-redis-cache-example

一、缓存概念知识

1、是什么缓存

我们日常生活中,经常会接触听到缓存这个词,例如,浏览器清空缓存,处理器缓存大小,磁盘缓存等等。经过分类,可以将缓存分为:

硬件缓存: 一般指的是机器上的 CPU、硬盘等等组件的缓存区间,一般是利用的内存作为一块中转区域,都通过内存交互信息,减少系统负载,提供传输效率。

客户端缓存: 一般指的是某些应用,例如浏览器、手机App、视频缓冲等等,都是在加载一次数据后将数据临时存储到本地,当再次访问时候先检查本地缓存中是否存在,存在就不必去远程重新拉取,而是直接读取缓存数据,这样来减少远端服务器压力和加快载入速度。

服务端缓存: 一般指远端服务器上,考虑到客户端请求量多,某些数据请求量大,这些热点数据经常要到数据库中读取数据,给数据库造成压力,还有就是 IO、网络等原因有一定延迟,响应客户端较慢。所以,在一些不考虑实时性的数据中,经常将这些数据存在内存中(内存速度非常快),当请求时候,能够直接读取内存中的数据及时响应。

2、为什么使用缓存

用缓存,主要有解决 高性能 与 高并发 与 减少数据库压力。缓存本质就是将数据存储在内存中,当数据没有发生本质变化的时候,我们应尽量避免直接连接数据库进行查询,因为并发高时很可能会将数据库压塌,而是应去缓存中读取数据,只有缓存中未查找到时再去数据库中查询,这样就大大降低了数据库的读写次数,增加系统的性能和能提供的并发量。

3、缓存的优缺点

优点:

  • 加快了响应速度

  • 减少了对数据库的读操作,数据库的压力降低。

缺点:

  • 内存容量相对硬盘小。

  • 缓存中的数据可能与数据库中数据不一致。

  • 因为内存断电就清空数据,存放到内存中的数据可能丢失。

二、Redis 概念知识

1、什么是 Redis

Redis 是一个高性能的 Key-Value 数据库,它是完全开源免费的,而且 Redis 是一个 NoSQL 类型数据库,是为了解决 高并发、高扩展,大数据存储 等一系列的问题而产生的数据库解决方案,是一个非关系型的数据库。但是,它也是不能替代关系型数据库,只能作为特定环境下的扩充。

2、为什么使用 Redis 作为缓存

支持高可用: Redis 支持 master\slave 主\从机制、sentinal 哨兵模式、cluster 集群模式,这样大大保证了 Redis 运行的稳定和高可用行。

支持多种数据结构: Redis 不仅仅支持简单的 Key/Value 类型的数据,同时还提供 list、set、zset、hash 等数据结构的存储。

支持数据持久化: 可以将内存中的数据持久化在磁盘中,当宕机或者故障重启时,可以再次加载进如 Redis,从而不会或减少数据的丢失。

有很多工具与插件对其支持: Redis 已经在业界广泛使用,已经是成为缓存的首选目标,所以很多语言和工具对其支持,我们只需要简单的操作就可以轻松使用。

3、Redis 支持的数据类型

Redis 支持的数据结构类型包括:

  • 字符串(string)

  • 哈希表(hash)

  • 列表(list)

  • 集合(set)

  • 有序集合(zset)

为了保证读取的效率,Redis 把数据对象都存储在内存当中,它可以支持周期性的把更新的数据写入磁盘文件中。而且它还提供了交集和并集,以及一些不同方式排序的操作。

三、缓存后可能遇见的问题

1、缓存穿透

缓存穿透: 指查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,造成缓存穿透。

缓存穿透几种解决办法:

  • 缓存空值,在从 DB 查询对象为空时,也要将空值存入缓存,具体的值需要使用特殊的标识, 能和真正缓存的数据区分开,另外将其过期时间设为较短时间。

  • 使用布隆过滤器,布隆过滤器能判断一个 key 一定不存在(不保证一定存在,因为布隆过滤器结构原因,不能删除,但是旧值可能被新值替换,而将旧值删除后它可能依旧判断其可能存在),在缓存的基础上,构建布隆过滤器数据结构,在布隆过滤器中存储对应的 key,如果存在,则说明 key 对应的值为空。

2、缓存击穿

缓存击穿: 某个 key 非常热点,访问非常频繁,处于集中式高并发访问的情况,当这个 key 在失效的瞬间,大量的请求就击穿了缓存,直接请求数据库,就像是在一道屏障上凿开了一个洞。

缓存击穿几种解决办法:

  • 设置二级缓存,或者设置热点缓存永不过期,需要根据实际情况进行配置。

  • 使用互斥锁,在执行过程中,如果缓存过期,那么先获取分布式锁,在执行从数据库中加载数据,如果找到数据就存入缓存,没有就继续该有的动作,在这个过程中能保证只有一个线程操作数据库,避免了对数据库的大量请求。

3、缓存雪崩

缓存雪崩: 当缓存服务器重启、或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统(比如DB)带来很大压力,造成数据库后端故障,从而引起应用服务器雪崩。

缓存雪崩几种解决办法:

  • 缓存组件设计高可用,缓存高可用是指,存储缓存的组件的高可用,能够防止单点故障、机器故障、机房宕机等一系列问题。例如 Redis sentinel 和 Redis Cluster,都实现了高可用。

  • 请求限流与服务熔断降级机制,限制服务请求次数,当服务不可用时快速熔断降级。

  • 设置缓存过期时间一定的随机分布,避免集中在同一时间缓存失效。

  • 定时更新缓存策略,对于实时性要求不高的数据,定时进行更新。

4、缓存一致性

使用缓存很大可能导致数据不一致问题,如下:

  • 更熟数据库成功 -> 更新缓存失败 -> 数据不一致

  • 更新缓存成功 -> 更新数据库失败 -> 数据不一致

  • 更新数据库成功 -> 淘汰缓存失败 -> 数据不一致

  • 淘汰缓存成功 -> 更新数据库失败 -> 查询缓存mis

所以使用缓存时候,应该结合实际情况,考虑缓存的数据是否有一致性需求。

四、SpringBoot 如何结合 Redis 实现缓存

1、Mavne 引入相关依赖

  • spring-boot-starter-data-redis:

  • commons-pool2:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId>
</dependency>

2、配置 Redis 参数

application 文件中添加连接 Redis 的配置参数

Redis 单机配置:

spring:redis:host: 127.0.0.1       #Redis 地址port: 6379            #Redis 端口号database: 0           #Redis 索引(0~15,默认为0)timeout: 1000         #Redis 连接的超时时间password: 123456      #Redis 密码,如果没有就默认不配置此参数lettuce:              #使用 lettuce 连接池pool:max-active: 20    #连接池最大连接数(使用负值表示没有限制)max-wait: -1      #连接池最大阻塞等待时间(使用负值表示没有限制)min-idle: 0       #连接池中的最大空闲连接max-idle: 10      #连接池中的最小空闲连接

Redis 哨兵配置:

spring:redis:sentinel:             #哨兵配置master: "my-master"nodes: "192.168.2.11:6379,192.168.2.12:6379,192.168.2.13:6379"database: 0           #Redis 索引(0~15,默认为0)timeout: 1000         #Redis 连接的超时时间password: 123456      #Redis 密码,如果没有就默认不配置此参数  lettuce:              #使用 lettuce 连接池pool:max-active: 20    #连接池最大连接数(使用负值表示没有限制)max-wait: -1      #连接池最大阻塞等待时间(使用负值表示没有限制)min-idle: 0       #连接池中的最大空闲连接max-idle: 10      #连接池中的最小空闲连接

Redis 集群配置:

spring:redis:cluster:              #redis 集群配置max-redirects: 5    #redis命令执行时最多转发次数nodes: "192.168.2.11:6379,192.168.2.12:6379,192.168.2.13:6379" database: 0           #Redis 索引(0~15,默认为0)timeout: 1000         #Redis 连接的超时时间password: 123456      #Redis 密码,如果没有就默认不配置此参数  lettuce:              #使用 lettuce 连接池pool:max-active: 20    #连接池最大连接数(使用负值表示没有限制)max-wait: -1      #连接池最大阻塞等待时间(使用负值表示没有限制)min-idle: 0       #连接池中的最大空闲连接max-idle: 10      #连接池中的最小空闲连接

3、配置 Spring 缓存管理器

@Configuration
public class RedisConfig {/*** 配置缓存管理器* @param factory Redis 线程安全连接工厂* @return 缓存管理器*/@Beanpublic CacheManager cacheManager(RedisConnectionFactory factory) {// 生成两套默认配置,通过 Config 对象即可对缓存进行自定义配置RedisCacheConfiguration cacheConfig = RedisCacheConfiguration.defaultCacheConfig()// 设置过期时间 10 分钟.entryTtl(Duration.ofMinutes(10))// 设置缓存前缀.prefixKeysWith("cache:user:")// 禁止缓存 null 值.disableCachingNullValues()// 设置 key 序列化.serializeKeysWith(keyPair())// 设置 value 序列化.serializeValuesWith(valuePair());// 返回 Redis 缓存管理器return RedisCacheManager.builder(factory).withCacheConfiguration("user", cacheConfig).build();}/*** 配置键序列化* @return StringRedisSerializer*/private RedisSerializationContext.SerializationPair<String> keyPair() {return RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer());}/*** 配置值序列化,使用 GenericJackson2JsonRedisSerializer 替换默认序列化* @return GenericJackson2JsonRedisSerializer*/private RedisSerializationContext.SerializationPair<Object> valuePair() {return RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer());}}

4、服务中使用 SpringCache 的注解

@Service
@CacheConfig(cacheNames = "user")
public class UserServiceImpl implements UserService {/*** 新增用户*/public User addUser(User user) {......}/*** 查询用户 */@Cacheable(key = "#username")public User getUserByUsername(String username) {......}/*** 更新用户 */@CachePut(key = "#user.username")public User updateUser(User user) {......}/*** 删除用户 */@CacheEvict(key = "#username")public void deleteByUsername(String username) {......}}

注解说明:

  • @CacheConfig:一般配置在类上,指定缓存名称,这个名称是和上面“置缓存管理器”中缓存名称的一致。

  • @Cacheable:作用于方法上,用于对于方法返回结果进行缓存,如果已经存在该缓存,则直接从缓存中获取,缓存的key可以从入参中指定,缓存的 value 为方法返回值。

  • @CachePut:作用于方法上,无论是否存在该缓存,每次都会重新添加缓存,缓存的key可以从入参中指定,缓存的value为方法返回值,常用作于更新。

  • @CacheEvict:作用于方法上,用于清除缓存

  • @Caching:作用于方法上,用于一次性设置多个缓存。

上面注解中的常用配置参数:

  • value:缓存管理器中配置的缓存的名称,这里可以理解为一个组的概念,缓存管理器中可以有多套缓存配置,每套都有一个名称,类似于组名,这个可以配置这个值,选择使用哪个缓存的名称,配置后就会应用那个缓存名称对应的配置。

  • key:缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合。

  • condition:缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存。

  • unless:不缓存的条件,和 condition 一样,也是 SpEL 编写,返回 true 或者 false,为 true 时则不进行缓存。

5、启动类添加开启缓存注解

@EnableCaching
@SpringBootApplication
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}}

@EnableCaching:作用于类上,用于开启注解功能。

五、SpringCache 操作缓存的不足

使用 Spring Cache 虽然方便,但是也有很多局限性,因为它多是根据请求参数命名 key,根据返回指设置 value,这样很多情况下,我们想方法内部进行命名和操作有一定的限制。如果我们需要灵活设置缓存,可以不用 SpringCache 提供的注解,直接在代码中使用 Spring-data-redis 包提供的方法,手动操作 key 与 value。

  • opsForValue().set(String key, String value);

  • opsForValue().get(String key);

@Autowired
private RedisTemplate<String, Object> redisTemplate;public void redisBatch(){// 设置值redisTemplate.opsForValue().set("key", "value");// 获取值redisTemplate.opsForValue().get("key");
}

还有经常要批量设置、读取缓存,可以使用:

  • opsForValue().multiSet(Map map);

  • opsForValue().multiGet(List list);

@Autowired
private RedisTemplate<String, Object> redisTemplate;public void redisBatch(){// 批量设置值Map<String,Object> map = new HashMap<>();map.put("test1","value1");map.put("test2","value2");map.put("test3","value3");redisTemplate.opsForValue().multiSet(map);// 批量获取值,如果某个 key 不存在,则返回值集合中对于的为 nullList<String> list = new ArrayList<>();list.add("test1");list.add("test2");list.add("test3");List<Object> valueList = redisTemplate.opsForValue().multiGet(list);
}

六、SpringBoot + SpringCache + Redis 示例项目

下面是一个简单的 SpringBoot 项目,用于对用户的增删改查,这里使用 SpringCache 来模拟对数据进行缓存,示例如下:

1、Mavne 引入相关依赖

Maven 中引入 SpringBoot 和 Redis 依赖,因为使用了

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.2.2.RELEASE</version></parent><groupId>mydlq.club</groupId><artifactId>springboot-redis-example</artifactId><version>0.0.1</version><name>springboot-redis-example</name><description>Demo project for Spring Boot Redis</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

2、配置连接 Redis 参数

spring:redis:host: 127.0.0.1port: 6379database: 0      timeout: 1000      password:         lettuce:        pool:max-active: 20   max-wait: -1    min-idle: 0      max-idle: 10

3、配置 Spring 缓存管理器

缓存配置类,里面配置缓存管理器,配置缓存的全局过期时间、序列化等参数。

import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.*;
import java.time.Duration;/*** Redis 配置类*/
@Configuration
public class RedisConfig {/*** 配置缓存管理器* @param factory Redis 线程安全连接工厂* @return 缓存管理器*/@Beanpublic CacheManager cacheManager(RedisConnectionFactory factory) {// 生成两套默认配置,通过 Config 对象即可对缓存进行自定义配置RedisCacheConfiguration cacheConfig1 = RedisCacheConfiguration.defaultCacheConfig()// 设置过期时间 10 分钟.entryTtl(Duration.ofMinutes(10))// 设置缓存前缀.prefixKeysWith("cache:user:")// 禁止缓存 null 值.disableCachingNullValues()// 设置 key 序列化.serializeKeysWith(keyPair())// 设置 value 序列化.serializeValuesWith(valuePair());RedisCacheConfiguration cacheConfig2 = RedisCacheConfiguration.defaultCacheConfig()// 设置过期时间 30 秒.entryTtl(Duration.ofSeconds(30)).prefixKeysWith("cache:user_info:").disableCachingNullValues().serializeKeysWith(keyPair()).serializeValuesWith(valuePair());// 返回 Redis 缓存管理器return RedisCacheManager.builder(factory).withCacheConfiguration("user", cacheConfig1).withCacheConfiguration("userInfo", cacheConfig2).build();}/*** 配置键序列化* @return StringRedisSerializer*/private RedisSerializationContext.SerializationPair<String> keyPair() {return RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer());}/*** 配置值序列化,使用 GenericJackson2JsonRedisSerializer 替换默认序列化* @return GenericJackson2JsonRedisSerializer*/private RedisSerializationContext.SerializationPair<Object> valuePair() {return RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer());}}

4、定义实体类

用户实体类 User

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;/*** 用户实体*/
@Data
public class User {private String username;@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)private String password;private String role;
}

用户信息实体类 UserInfo

import lombok.Data;/*** 用户信息实体*/
@Data
public class UserInfo {private String name;private String sex;private Integer age;
}

5、定义服务接口

UserService

import mydlq.club.example.entity.User;/*** 用户业务接口*/
public interface UserService {/*** 增加账户** @param user 账户*/void addUser(User user);/*** 获取账户** @param username 用户名* @return 用户信息*/User getUserByUsername(String username);/*** 修改账户** @param user 用户信息* @return 用户信息*/User updateUser(User user);/*** 删除账户* @param username 用户名*/void deleteByUsername(String username);}

UserInfoService

import mydlq.club.example.entity.UserInfo;/*** 用户信息业务接口*/
public interface UserInfoService {/*** 增加用户信息** @param userInfo 用户信息*/void addUserInfo(UserInfo userInfo);/*** 获取用户信息** @param name 姓名* @return 用户信息*/UserInfo getByName(String name);/*** 修改用户信息** @param userInfo 用户信息* @return 用户信息*/UserInfo updateUserInfo(UserInfo userInfo);/*** 删除用户信息* @param name 姓名*/void deleteByName(String name);}

6、实现服务类

实现 UserService 与 UserInfoService 接口中的方法,里面使用 @Cacheable、@CachePut、@CacheEvict 三个注解完成对用户与用户信息数据的缓存。

UserServiceImpl(用户业务实现类)

注意,为了演示方便,没有连接数据库,临时创建了个成员变量 userMap 来模拟数据库存储。

import mydlq.club.example.entity.User;
import mydlq.club.example.service.UserService;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import java.util.HashMap;@Service
@CacheConfig(cacheNames = "user")
public class UserServiceImpl implements UserService {private HashMap<String, User> userMap = new HashMap<>();@Overridepublic void addUser(User user) {userMap.put(user.getUsername(), user);}@Override@Cacheable(key = "#username",unless = "#result==null ")public User getUserByUsername(String username) {if (!userMap.containsKey(username)) {return null;}return userMap.get(username);}@Override@CachePut(key = "#user.username")public User updateUser(User user) {if (!userMap.containsKey(user.getUsername())){throw new RuntimeException("不存在该用户");}// 获取存储的对象User newUser = userMap.get(user.getUsername());// 复制要更新的数据到新对象,因为不能更改用户名信息,所以忽略BeanUtils.copyProperties(user, newUser, "username");// 将新的对象存储,更新旧对象信息userMap.put(newUser.getUsername(), newUser);// 返回新对象信息return newUser;}@Override@CacheEvict(key = "#username")public void deleteByUsername(String username) {userMap.remove(username);}}

UserInfoServiceImpl(用户信息业务实现)

注意,为了演示方便,没有连接数据库,临时创建了个成员变量 userInfoMap 来模拟数据库存储。

import mydlq.club.example.entity.UserInfo;
import mydlq.club.example.service.UserInfoService;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import java.util.HashMap;@Service
@CacheConfig(cacheNames = "userInfo")
public class UserInfoServiceImpl implements UserInfoService {private HashMap<String, UserInfo> userInfoMap = new HashMap<>();@Overridepublic void addUserInfo(UserInfo userInfo) {userInfoMap.put(userInfo.getName(), userInfo);}@Override@Cacheable(key = "#name", unless = "#result==null")public UserInfo getByName(String name) {if (!userInfoMap.containsKey(name)) {return null;}return userInfoMap.get(name);}@Override@CachePut(key = "#userInfo.name")public UserInfo updateUserInfo(UserInfo userInfo) {if (!userInfoMap.containsKey(userInfo.getName())) {throw new RuntimeException("该用户信息没有找到");}// 获取存储的对象UserInfo newUserInfo = userInfoMap.get(userInfo.getName());// 复制要更新的数据到新对象,因为不能更改用户名信息,所以忽略BeanUtils.copyProperties(userInfo, newUserInfo, "name");// 将新的对象存储,更新旧对象信息userInfoMap.put(newUserInfo.getName(), newUserInfo);// 返回新对象信息return newUserInfo;}@Override@CacheEvict(key = "#name")public void deleteByName(String name) {userInfoMap.remove(name);}}

7、创建 Controller

UserController

import mydlq.club.example.entity.User;
import mydlq.club.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;/*** 用户 Controller*/
@RestController
public class UserController {@Autowiredprivate UserService userService;@GetMapping("/user/{username}")public User getUser(@PathVariable String username) {return userService.getUserByUsername(username);}@PostMapping("/user")public String createUser(@RequestBody User user) {userService.addUser(user);return "SUCCESS";}@PutMapping("/user")public User updateUser(@RequestBody User user) {return userService.updateUser(user);}@DeleteMapping("/user/{username}")public String deleteUser(@PathVariable String username) {userService.deleteByUsername(username);return "SUCCESS";}}

UserInfoController

import mydlq.club.example.entity.UserInfo;
import mydlq.club.example.service.UserInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;/*** 用户信息 Controller*/
@RestController
public class UserInfoController {@Autowiredprivate UserInfoService userInfoService;@GetMapping("/userInfo/{name}")public UserInfo getUserInfo(@PathVariable String name) {return userInfoService.getByName(name);}@PostMapping("/userInfo")public String createUserInfo(@RequestBody UserInfo userInfo) {userInfoService.addUserInfo(userInfo);return "SUCCESS";}@PutMapping("/userInfo")public UserInfo updateUserInfo(@RequestBody UserInfo userInfo) {return userInfoService.updateUserInfo(userInfo);}@DeleteMapping("/userInfo/{name}")public String deleteUserInfo(@PathVariable String name) {userInfoService.deleteByName(name);return "SUCCESS";}}

8、启动类

启动类中添加 @EnableCaching 注解开启缓存。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@EnableCaching
@SpringBootApplication
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}}

END

Java面试题专栏

【41期】盘点那些必问的数据结构算法题之链表

【42期】盘点那些必问的数据结构算法题之二叉堆

【43期】盘点那些必问的数据结构算法题之二叉树基础

【44期】盘点那些必问的数据结构算法题之二分查找算法

【45期】盘点那些必问的数据结构算法题之基础排序

【46期】盘点那些必问的数据结构算法题之快速排序

【47期】六大类二叉树面试题汇总解答

【48期】盘点Netty面试常问考点:什么是 Netty 的零拷贝?

【49期】面试官:SpringMVC的控制器是单例的吗?

【50期】基础考察:ClassNotFoundException 和 NoClassDefFoundError 有什么区别

欢迎长按下图关注公众号后端技术精选

SpringBoot 结合 Spring Cache 操作 Redis 实现数据缓存相关推荐

  1. redis lettuce 超时_Spring Cache 操作 Redis 实现数据缓存(上)

    点击上方☝SpringForAll社区 轻松关注!及时获取有趣有料的技术文章 本文来源:http://www.mydlq.club/article/55/ . 一.缓存概念知识 . 1.是什么缓存 . ...

  2. springboot整合spring @Cache和Redis

    转载自  springboot整合spring @Cache和Redis spring基于注解的缓存 对于缓存声明,spring的缓存提供了一组java注解: @Cacheable:触发缓存写入. @ ...

  3. spring boot 缓存_Spring Boot 集成 Redis 实现数据缓存

    Spring Boot 集成 Redis 实现数据缓存,只要添加一些注解方法,就可以动态的去操作缓存了,减少代码的操作. 在这个例子中我使用的是 Redis,其实缓存类型还有很多,例如 Ecache. ...

  4. SpringBoot+Redis完成数据缓存(内容丰富度一定超出你的想象)

    SpringBoot+Redis完成数据缓存 去年今日此门中 人面桃花相映红 人面不知何处去 桃花依旧笑春风 感谢相遇!感谢自己,努力的样子很给力! 为了更多朋友看见,还是和大家说一声抱歉,限制为粉丝 ...

  5. Spring整合Redis做数据缓存(Windows环境)

    当我们一个项目的数据量很大的时候,就需要做一些缓存机制来减轻数据库的压力,提升应用程序的性能,对于java项目来说,最常用的缓存组件有Redis.Ehcache和Memcached. Ehcache是 ...

  6. springboot中使用RedisTemplate操作redis遇到的问题

    首先说说问题, 在springboot中使用RedisTemplate操作redis时候,通过redis工具发现存入redis的数据的键为空 ,如下图: 点击空的键,弹出错误提示:不能打开值的标签,不 ...

  7. Spring Boot 操作 Redis教程

    Spring Boot 操作 Redis教程 在 Redis 出现之前,我们的缓存框架各种各样,有了 Redis ,缓存方案基本上都统一了 使用 Java 操作 Redis 的方案很多,Jedis 是 ...

  8. Redis进阶-Jedis以及Spring Boot操作 Redis 5.x Cluster

    文章目录 Pre Jedis操作Redis Cluster 添加依赖 Code Spring Boot 操作Redis Cluster 引入 依赖 application.yml Code Pre R ...

  9. Redis概述_使用命令对redis的数据进行增删改查_Jedis连接redis进行数据操作_redis进行数据缓存案例

    学习目标 redis 概念 下载安装 命令操作 1. 数据结构 持久化操作 使用Java客户端操作redis Redis 前言(从百度上抄的, 看看了解一下, 懒得排版了) 1. 概念: redis是 ...

最新文章

  1. https://www.adminsub.net/tcp-udp-port-finder/14000 ——查找tcp端口对应的服务 可以看某些端口是否让恶意软件开启...
  2. Teams Bot开发系列:Middleware
  3. 第1次作业:阅读优秀博文谈感想
  4. renderTo:Ext.getBody()的意思
  5. 用C#实现软件自动更新
  6. 【算法1-2】排序(今天刷洛谷了嘛)
  7. python 使用 with open() as 读写文件-给Python学习者的文件读写指南(含基础与进阶)...
  8. 数据科学 IPython 笔记本 7.14 处理时间序列
  9. 称重问题 —— 哪个是假币?
  10. Java clone克隆方法 --深拷贝--浅拷贝 --原型模型
  11. 从零学Java(10)之方法详解,喷打野你真的没我6!
  12. 零售商店销售管理系统——第四周
  13. 【Burp Suite实战指南】【定期更新】
  14. android 11如何剪裁上传图片
  15. 基于眨眼状态的在线疲劳检测系统(Matlab-GUI设计)
  16. 用友U9sv服务打开时报错内存入口检查失败,因为可用内存(371662848 字节)少于总内存的 5%
  17. Java虚拟机部分知识点
  18. 如何使用kindle
  19. 单片机实现温度传感器
  20. 关于Mybatisplus查询到字段无法映射的问题

热门文章

  1. 阿里云万网域名解析免费教程
  2. Dubbo-SPI(五)-@Activate注解
  3. 2021《香帅中国财富报告25讲》思维导图
  4. 回到深圳的感觉太好了
  5. android studio : connection refused
  6. 2023年全国职业院校技能大赛 高等职业教育组(信息安全与评估赛项)
  7. tomcat是虚拟服务器吗,tomcat 虚拟主机是什么意思
  8. android aapt关闭检测,Android自动化打包之一:aapt的用法
  9. Android复制手机号码到剪切板并调起打电话功能
  10. Linux Poll机制