欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 产业 > SpringCache的入门使用以及在项目里的案例

SpringCache的入门使用以及在项目里的案例

2025/2/24 21:49:47 来源:https://blog.csdn.net/weixin_55592317/article/details/142441878  浏览:    关键词:SpringCache的入门使用以及在项目里的案例

今天在项目中用到了SpringCache,也首次面试会问的各种缓存问题,话不多说进行正题。

几种基本注解的使用

1. @Cacheable

@Cacheable 是 Spring Cache 中最常用的注解,用于将方法的返回结果缓存起来,以后再调用该方法时,如果缓存中已有结果,就不执行方法,而是直接返回缓存中的结果。

用法

@Cacheable(value = "users", key = "#userId")
public User getUserById(Long userId) {// 查询数据库return userRepository.findById(userId).orElse(null);
}
  • value:指定缓存的名称,比如 "users"
  • key:指定缓存的 key,默认使用方法参数。如果不指定,Spring Cache 会自动使用方法参数作为 key。

常见属性

  • condition:可以设置条件,只有满足条件时才缓存。
  • unless:可以设置条件,满足条件时不缓存。
  • sync:设置为 true,可以防止缓存击穿,确保同一时刻只有一个线程能查询数据库并将结果缓存。

示例

@Cacheable(value = "users", key = "#userId", condition = "#userId > 0", unless = "#result == null")
public User getUserById(Long userId) {return userRepository.findById(userId).orElse(null);
}

2. @CachePut

@CachePut 表示不管缓存中是否有值,都会执行方法并将结果放入缓存。常用于更新缓存。

用法

@CachePut(value = "users", key = "#user.id")
public User updateUser(User user) {// 更新数据库return userRepository.save(user);
}
  • value:缓存的名称。
  • key:指定缓存的 key。

@CachePut 每次都会执行方法,并将返回值放入缓存中,用于保证缓存与数据库数据的一致性。

3. @CacheEvict

@CacheEvict 用于从缓存中移除数据,常用于删除或更新数据时同步清除缓存。

用法

@CacheEvict(value = "users", key = "#userId")
public void deleteUser(Long userId) {// 删除数据库中的用户userRepository.deleteById(userId);
}
  • value:缓存的名称。
  • key:要移除的缓存的 key。

常见属性

  • allEntries = true:删除该缓存名称下的所有缓存。
  • beforeInvocation = true:在方法执行前清除缓存,默认是 false,即方法执行后再清除缓存。

示例

@CacheEvict(value = "users", allEntries = true)
public void clearAllUsersCache() {// 清除所有缓存
}

4. @Caching

@Caching 可以同时组合使用多个缓存相关的注解,适用于复杂的缓存操作。

用法

@Caching(put = { @CachePut(value = "users", key = "#user.id") },evict = { @CacheEvict(value = "cacheName", key = "#user.id") }
)
public User saveOrUpdateUser(User user) {return userRepository.save(user);
}

通过 @Caching,你可以同时定义多个 @Cacheable@CachePut@CacheEvict 注解,完成复杂的缓存逻辑。

5. @CacheConfig

@CacheConfig 用于类级别的注解,统一配置缓存的名称和其它属性,减少重复配置。

用法

@CacheConfig(cacheNames = "users")
public class UserService {@Cacheable(key = "#userId")public User getUserById(Long userId) {return userRepository.findById(userId).orElse(null);}@CachePut(key = "#user.id")public User updateUser(User user) {return userRepository.save(user);}
}
  • cacheNames:指定默认的缓存名称,类中所有的缓存注解会默认使用这个名称。

小结:

  • @Cacheable:将方法的返回结果缓存。
  • @CachePut:更新缓存,即使缓存中有数据,也会重新执行方法并更新缓存。
  • @CacheEvict:从缓存中移除数据。
  • @Caching:组合多个缓存注解。
  • @CacheConfig:类级别统一配置缓存名称等属性。


配置

要使用SpringCache需要首先开启配置:

1. 引入依赖

首先,在你的 pom.xml 中添加 Spring Cache 相关的依赖,如果你使用的是基于内存的缓存(如 ConcurrentMapCache),可以使用如下依赖:

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

如果你打算使用 Redis、EhCache 等其他缓存实现,还需要引入对应的依赖,例如 Redis 缓存:

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

2. 开启缓存支持

在你的主类Application或任意配置类上加上 @EnableCaching 注解:

import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Configuration;@Configuration
@EnableCaching
public class CacheConfig {// 你可以在这里配置缓存相关的 Bean 或者使用默认配置
}
@SpringBootApplication
@EnableScheduling
@EnableCaching
public class MyAppApplication {//也可以在主类上面加public static void main(String[] args) {SpringApplication.run(MyAppApplication.class, args);}}

3. 配置缓存(可选)

Spring Boot 默认使用 ConcurrentMapCache,即内存中的缓存。如果需要使用其他缓存实现,你可以在 application.properties 中进行配置。比如使用 Redis 缓存:

  # Redisdata:redis:port: 6379host: ${your_host}password: ${pwd_if_needed}# Cachecache:type: redis # 使用redis作为cache

4. 使用缓存注解

一旦启用缓存支持后,你就可以使用 @Cacheable, @CachePut, @CacheEvict 等注解进行缓存操作。

小结:

  • 引入依赖:添加 spring-boot-starter-cache 依赖。
  • 开启缓存:在配置类上加 @EnableCaching
  • 配置缓存类型:在 application.properties 中配置缓存类型(如 Redis 或默认内存缓存)。
  • 使用注解:在服务方法上使用 @Cacheable, @CachePut, @CacheEvict 等缓存注解。

这就完成了 Spring Cache 的基本配置和开启。





现在再来说说在最近实际项目中的应用

JwtFilter:

在用户登陆的时候根据Token里解析出来的id去查询数据库,将查询的结果进行缓存,最终返回一个LoginUser对象给SringSecurity认证。

  /*** parse the token and get the user information to create a LoginUser object* @param token token to parse* @return LoginUser object* @throws UsernameNotFoundException if the user is not found* @Description: get the newest user information from the database if the user is not in the cache!*/private LoginUser getLoginUser(String token) {// Parse the token to get the user informationMap<String, Object> claims = jwtUtil.parseToken(token);// get the user information from the database can make sure the user is up to dateLong userId = Long.parseLong(claims.get("userId").toString());// if the user is not in the cache, get the user from the databaseUser user = cachedUserService.getUserById(userId);if (user != null) {user.setPassword(null);// 不将密码传递保存在redis中}else {throw new UsernameNotFoundException("User not found");}List<String> roles = cachedUserService.getRolesByUserId(userId);List<String> permissions = cachedUserService.getPermissionsByUserId(userId);return new LoginUser(user, permissions, roles);}

这里cachedUserService就是专门用来在经过jwtfilter的是手查询用户的最新的信息的,减少数据库的负担。


/*** @Author: Yupeng Li* @Date: 22/9/2024 02:58* @Description: This class is used to cache user, role and permission data in Redis cache.* when a new API request comes in, it will go through the JWT filter,* and then the CachedUserService will be called to get the user, role and permission data from the cache.* <p>* If the data is not in the cache, it will be fetched from the database and then stored in the cache.* If the data is already in the cache, it will be fetched from the cache directly.* <p>* when the user, role and permission data is updated, the cache will be evicted.* <p>* The aim of this class is to reduce the number of database queries and improve the performance of the application.*/
@Service
public class CachedUserService {@Resourceprivate UserMapper userMapper;@Resourceprivate RoleMapper roleMapper;@Resourceprivate PermissionMapper permissionMapper;private static final Logger logger = LoggerFactory.getLogger(CachedUserService.class);@Cacheable(value = "users", key = "#userId")public User getUserById(Long userId) {return userMapper.finUserById(userId);}@Cacheable(value = "roles", key = "#userId")public List<String> getRolesByUserId(Long userId) {return roleMapper.findRolesByUserId(userId);}@Cacheable(value = "permissions", key = "#userId")public List<String> getPermissionsByUserId(Long userId) {return permissionMapper.findPermissionsByUserId(userId);}@CacheEvict(value = "users", key = "#userId")public void evictUserCache(Long userId) {logger.info("User cache evicted: {}", userId);}@CacheEvict(value = "roles", key = "#userId")public void evictRolesCache(Long userId) {logger.info("Roles cache evicted: {}", userId);}@CacheEvict(value = "permissions", key = "#userId")public void evictPermissionsCache(Long userId) {logger.info("Permissions cache evicted: {}", userId);}
}

这里有一个坑要提别的提醒大家,就是在这个CachedUserService里面你不能直接在这个类里面去调用其他方法。比如你这个类里面有个evictAllCahe()这个方法,你想在这个方法里面直接调用其他的三个方法evictRolesCache()evictUserCache()evictPermissionsCache()很负责任的告诉你,当你在其他类里面调用evictAllCahe()企图删除所有缓存时是不会生效的。方法可以执行,但是缓存不会被删除,别问我怎么知道的(被坑惨了哈哈哈。


主要原因好像是Spring的AOP机制什么什么的,没了解太深。反转正确的做法就是你吧evictAllCahe()这个方法写到其他类里面去然后再调用就可以了,同一个类里面就不行!

public class LoginServiceImpl {protected ResponseEntity<Result> completeProfileUpdate(User user) {......// 每当用户更新profile,移除所有的用户缓存,以便下次查询时重新加载数据!evictAllUserCaches(user.getId());......return ResponseEntity.ok(Result.success("Profile updated successfully"));}/*** 移除所有用户缓存* @param userId 用户ID*/private void evictAllUserCaches(Long userId) {cachedUserService.evictUserCache(userId);cachedUserService.evictRolesCache(userId);cachedUserService.evictPermissionsCache(userId);}}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词