Spring Cache 缓存
缓存不生效的原因核心原因queryUserInfo通过this.queryByUserName(userName)调用属于内部调用绕过了 Spring AOP 代理因此Cacheable不会生效。 原理说明Spring Cache 基于AOP 代理实现外部调用userService.queryByUserName(...)→ 经过代理 → 缓存拦截器生效 ✅内部调用this.queryByUserName(...)→ 直接调用原始方法 → 缓存拦截器不生效 ❌你的调用链javaqueryUserInfo() { // ❌ this.queryByUserName() 是内部调用缓存不生效 UserDTO user queryByUserName(userName); }✅ 解决方案方案一将queryByUserName方法注入自身推荐javaService public class UserServiceImpl implements UserService { Autowired private UserService self; // 注入自身代理对象 Override public String queryUserInfo(String userName) { // ✅ 通过代理对象调用缓存生效 UserDTO user self.queryByUserName(userName); // ... } Override Cacheable(value UserConstants.CACHE_USER, key #userName) public UserDTO queryByUserName(String userName) { System.out.println(###############################################); return userMapper.selectByUserName(userName); } }方案二将缓存方法移到单独的 Service更解耦javaService public class UserCacheService { Cacheable(value UserConstants.CACHE_USER, key #userName) public UserDTO queryByUserName(String userName) { return userMapper.selectByUserName(userName); } } Service public class UserServiceImpl implements UserService { Autowired private UserCacheService userCacheService; public String queryUserInfo(String userName) { UserDTO user userCacheService.queryByUserName(userName); // ... } }方案三使用AopContext.currentProxy()不推荐javaUserService proxy (UserService) AopContext.currentProxy(); UserDTO user proxy.queryByUserName(userName);需在启动类上添加EnableAspectJAutoProxy(exposeProxy true)。 验证方法第一次调用queryUserInfo会打印###############################################第二次调用同一userName如果缓存生效不应打印该行。若每次都打印说明仍是内部调用问题。 其他排查点已确认的EnableCaching是否存在→ 检查启动类UserConstants.CACHE_USER是否有效→ 需为字符串如users返回值是否可序列化→UserDTO需实现SerializableuserName参数是否变化→ 相同值才能命中缓存✅ 推荐方案方案一最简洁改动小立即生效。package com.weiyu.modules.system.service.impl; import com.alibaba.fastjson.JSON; import com.weiyu.framework.exception.BusinessException; import com.weiyu.framework.util.AesUtils; import com.weiyu.modules.system.constant.UserConstants; import com.weiyu.modules.system.context.UserContext; import com.weiyu.modules.system.converter.UserConverter; import com.weiyu.modules.system.dto.UserDTO; import com.weiyu.modules.system.dto.request.UserCreateRequest; import com.weiyu.modules.system.dto.request.UserUpdateRequest; import com.weiyu.modules.system.entity.Account; import com.weiyu.modules.system.enums.UserDataCommand; import com.weiyu.modules.system.mapper.UserMapper; import com.weiyu.modules.system.service.AccountService; import com.weiyu.modules.system.service.UserService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import java.util.ArrayList; import java.util.List; import java.util.Objects; /** * 用户 */ Service RequiredArgsConstructor Slf4j public class UserServiceImpl implements UserService { private final UserMapper userMapper; // 注入用户自身服务解决 queryByUserName 缓存不生效的问题 // queryUserInfo 通过 this.queryByUserName(userName) 调用属于 内部调用绕过了 Spring AOP 代理因此 Cacheable 不会生效。 private final UserService userService; private final AccountService accountService; private final UserConverter userConverter; /** * 根据用户名/账号查询用户信息 * * param userName 用户名/账号 * return 用户对象 */ Override Cacheable(value UserConstants.CACHE_USER, key #userName) public UserDTO queryByUserName(String userName) { System.out.println(###############################################); return userMapper.selectByUserName(userName); } /** * 新增用户 * * param createRequest 用户创建请求对象 */ Override public void add(UserCreateRequest createRequest) { // 业务实现预留 } /** * 修改用户信息 * * param userUpdateRequest 用户更新请求对象 */ Override public void update(UserUpdateRequest userUpdateRequest) { // 业务实现预留 } /** * 根据数据指令查询用户列表 * * param userName 用户名/账号 * param dataCommand 数据指令 * param id 业务 ID * return 用户列表 */ Override public ListUserDTO queryUsers(String userName, UserDataCommand dataCommand, Integer id) { // 初始化空集合避免返回null ListUserDTO userDTOs new ArrayList(8); switch (dataCommand) { case ALL: userDTOs userMapper.selectAllUsers(); break; case VALID: userDTOs userMapper.selectValidUsers(); break; case ASSAY_TASK_ASSAYER: userDTOs userMapper.selectAssayTaskAssayers(id); break; case TEST_REPORT_VERIFIER: userDTOs userMapper.selectTestReportVerifiers(userName); break; case TEST_REPORT_ISSUER: userDTOs userMapper.selectTestReportIssuers(userName); break; case WSPJ_REPORT_VERIFIER: userDTOs userMapper.selectWspjReportVerifiers(userName); break; case WSPJ_REPORT_ISSUER: userDTOs userMapper.selectWspjReportIssuers(userName); break; default: log.warn(不支持的用户列表查询指令:{}, dataCommand); } // 空集合防护 return CollectionUtils.isEmpty(userDTOs) ? new ArrayList() : userDTOs; } /** * 查询用户签名图片 * * param userName 用户名/账号 * return 签名图片字节数组 */ Override public byte[] queryUserSignatureImage(String userName) { Listbyte[] images userMapper.selectUserSignatureImages(userName); // 双重非空判断 if (!CollectionUtils.isEmpty(images)) { return images.get(0); } return new byte[0]; } /** * 获取用户上下文信息 * * param userName 用户名/账号 * return 用户上下文 */ Override public UserContext getUserContext(String userName) { UserDTO userDTO queryByUserName(userName); return Objects.isNull(userDTO) ? null : userConverter.toContext(userDTO); } /** * 获取用户信息普通用户 超级用户兼容 * * param userName 用户名/账号 * return 加密的用户信息 */ Override public String queryUserInfo(String userName) { try { // 1. 查询普通用户信息 // 通过内部调用 queryByUserName 或 this.queryByUserName 绕过 Spring AOP 代理Cacheable 缓存不生效。 // UserDTO user this.queryByUserName(userName); // 通过外部调用 userService.queryByUserName 经过 Spring AOP 代理Cacheable 缓存生效。 UserDTO user userService.queryByUserName(userName); // 2. 处理超级用户逻辑 if (user null) { Account account accountService.queryAccount(userName); // 空指针防护 if (account ! null UserConstants.SUPER_ACCOUNT_TYPE.equals(account.getType().ordinal())) { user new UserDTO(); user.setUserName(account.getAccount()); user.setRealName(account.getAccount()); user.setDeptName(UserConstants.SUPER_USER_DEPT_NAME); } } // 3. 对象序列化 String userJsonStr JSON.toJSONString(user); // 4. 返回加密的用户信息 return AesUtils.encrypt(userJsonStr); } catch (Exception e) { log.error(获取用户加密信息异常, e); throw new BusinessException(查询用户信息失败); } } /** * 查询用户角色 * * param userName 用户名/账号 * return 用户角色 */ Override public String queryUserRole(String userName) { return userMapper.selectUserRoleByUserName(userName); } }

相关新闻

深度解析OpenArk内核模式加载失败问题:实战解决方案与技术架构

深度解析OpenArk内核模式加载失败问题:实战解决方案与技术架构

深度解析OpenArk内核模式加载失败问题:实战解决方案与技术架构 【免费下载链接】OpenArk The Next Generation of Anti-Rookit(ARK) tool for Windows. 项目地址: https://gitcode.com/GitHub_Trending/op/OpenArk OpenArk作为Windows平台上的下一代反Rootki…

2026/8/11 19:16:59 阅读更多 →
CSDN博客下载器:3步实现技术文章永久保存的完整指南

CSDN博客下载器:3步实现技术文章永久保存的完整指南

CSDN博客下载器:3步实现技术文章永久保存的完整指南 【免费下载链接】CSDNBlogDownloader 项目地址: https://gitcode.com/gh_mirrors/cs/CSDNBlogDownloader 你是否曾为CSDN上的优质技术文章无法离线保存而烦恼?CSDN博客下载器正是解决这一痛点…

2026/8/11 19:15:58 阅读更多 →
告别编程门槛:用h5maker开源编辑器,5分钟创建专业H5页面

告别编程门槛:用h5maker开源编辑器,5分钟创建专业H5页面

告别编程门槛:用h5maker开源编辑器,5分钟创建专业H5页面 【免费下载链接】h5maker h5编辑器类似maka、易企秀 账号/密码:admin 项目地址: https://gitcode.com/gh_mirrors/h5/h5maker 你是否曾为制作H5页面而头疼?是否因为…

2026/8/11 19:15:58 阅读更多 →

最新新闻

Windows下Tomcat 10/11手动配置、部署与故障排查全指南

Windows下Tomcat 10/11手动配置、部署与故障排查全指南

1. 项目概述:为什么在Windows上手动配置Tomcat依然重要? 如果你是一名Java后端开发者,或者正在学习Java Web开发,那么Tomcat这个名字你一定不陌生。作为一款轻量级、应用广泛的Web应用服务器,它几乎是每个Java开发者绕…

2026/8/11 19:56:14 阅读更多 →
如何在Windows/Linux/Mac上快速搭建Comskip:从依赖安装到编译运行的完整教程

如何在Windows/Linux/Mac上快速搭建Comskip:从依赖安装到编译运行的完整教程

如何在Windows/Linux/Mac上快速搭建Comskip:从依赖安装到编译运行的完整教程 【免费下载链接】Comskip A free commercial detector 项目地址: https://gitcode.com/gh_mirrors/co/Comskip Comskip是一款免费的广告检测工具,能够帮助用户自动识别…

2026/8/11 19:56:13 阅读更多 →
IntelliJ IDEA 首次安装高效配置指南:从零打造个性化开发环境

IntelliJ IDEA 首次安装高效配置指南:从零打造个性化开发环境

1. 项目概述:为什么说“首次设置”是开发效率的分水岭?每次打开全新的IntelliJ IDEA,面对那个干净得有点“陌生”的界面,你是不是既兴奋又有点无从下手?兴奋的是终于可以开始新项目了,无从下手是因为默认的…

2026/8/11 19:56:13 阅读更多 →
写材料的ai软件怎么用?材料星有哪些功能值得用?写的公文质量怎么样

写材料的ai软件怎么用?材料星有哪些功能值得用?写的公文质量怎么样

写材料的ai软件怎么用?拿材料星举例,材料星值得用的功能集中在对话写作、知识库、润色纠错和一键排版这几块。这篇从一个常用者的角度,说清这些功能怎么串成一条线,以及用下来公文质量到底怎么样。一、材料星有哪些功能值得用写材…

2026/8/11 19:56:13 阅读更多 →
一个 computeIfAbsent 嵌套调用,把单核打满并且永不退出:ConcurrentHashMap 的 4 个致命细节

一个 computeIfAbsent 嵌套调用,把单核打满并且永不退出:ConcurrentHashMap 的 4 个致命细节

title: 一个 computeIfAbsent 嵌套调用,把单核打满并且永不退出:ConcurrentHashMap 的 4 个致命细节 tags: [Java, 并发编程, ConcurrentHashMap, JDK源码, CAS] category: Java 后端 一个永远跑不完的定时任务 我们有个配置解析服务,每 5 分…

2026/8/11 19:56:13 阅读更多 →
Hanselman.Forms发布指南:Android与iOS应用商店上架全攻略

Hanselman.Forms发布指南:Android与iOS应用商店上架全攻略

Hanselman.Forms发布指南:Android与iOS应用商店上架全攻略 【免费下载链接】Hanselman.Forms The most awesome Hanselman app 项目地址: https://gitcode.com/gh_mirrors/ha/Hanselman.Forms Hanselman.Forms是一款功能强大的跨平台应用,本指南将…

2026/8/11 19:55:13 阅读更多 →

日新闻

如何用Video2X实现专业级视频画质提升:AI视频增强完整指南

如何用Video2X实现专业级视频画质提升:AI视频增强完整指南

如何用Video2X实现专业级视频画质提升:AI视频增强完整指南 【免费下载链接】video2x A machine learning-based video super resolution and frame interpolation framework. Est. Hack the Valley II, 2018. 项目地址: https://gitcode.com/GitHub_Trending/vi/v…

2026/8/11 0:00:02 阅读更多 →
前后端分离项目中控制台与接口工具数据差异排查指南

前后端分离项目中控制台与接口工具数据差异排查指南

1. 问题现象解析:控制台与Apifox的数据差异 最近在调试一个前后端分离项目时,遇到了一个典型问题:后端服务在本地开发环境控制台能正常输出查询数据,但通过Apifox测试时却返回空结果。这种"控制台有数据,接口工具…

2026/8/11 0:00:03 阅读更多 →
AI编程实战:从Claude Code踩坑到游戏开发入门

AI编程实战:从Claude Code踩坑到游戏开发入门

1. 从“AI能帮我做游戏”到“AI让我重新学编程”最近身边不少朋友,尤其是一些非技术背景、但对游戏开发有浓厚兴趣的朋友,都在问我同一个问题:“听说现在用Claude Code这种AI编程工具,小白也能做游戏了,是真的吗&#…

2026/8/11 0:00:03 阅读更多 →

周新闻

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁 【免费下载链接】baidupankey 在线查询网盘提取码(维护中 rm repo) 项目地址: https://gitcode.com/gh_mirrors/ba/baidupankey 你是否曾经在深夜寻找一份重要资料&#x…

2026/8/11 1:08:05 阅读更多 →
如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南 【免费下载链接】chinese_license_plate_generator 中国车牌生成器 项目地址: https://gitcode.com/gh_mirrors/ch/chinese_license_plate_generator 中国车牌生成器是一个基于Python的开源项目&#xff0c…

2026/8/11 1:08:05 阅读更多 →
收藏!小白程序员轻松入门大模型,从Harness工程开始实践

收藏!小白程序员轻松入门大模型,从Harness工程开始实践

文章强调学习大模型不应只关注模型本身,而应重视模型外的系统搭建,即Harness。提出AgentModelHarness的实用公式,详细介绍Harness的四个层次:持久化层、执行层、控制层和观察与验证层。文章还探讨了上下文工程、工具设计、AGENTS.…

2026/8/11 1:08:05 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/11 17:09:45 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/11 1:08:06 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/11 17:09:45 阅读更多 →