缓存用户信息
因为用户信息不是经常需要修改的 可以将用户信息存储至Redis中 不但可以减轻数据库的压力 而且可以更快的将用户的数据查询出来
在BaseController中顶一个redis字段用于标识用户信息
protected static final String REDIS_USER_CACHE = "redis_user_cache";
缓存思路:
- 从redis中根据id查询用户信息 如果有用户信息 直接使用Jackson将json转换成用户信息对象返回
- 若redis中无数据 从数据库中查询用户信息 并保存至Redis中
private AppUser getUser(String userId) {
String redisUser = redisOperator.get(REDIS_USER_CACHE + ":" + userId);
AppUser appUser = null;
if (StringUtils.isBlank(redisUser)) {
appUser = userService.getUser(userId);
String appUserJson = JsonUtil.objectForJson(appUser);
redisOperator.set(REDIS_USER_CACHE + ":" + userId, appUserJson);
} else {
appUser = JsonUtil.jsonToObject(redisUser, AppUser.class);
}
return appUser;
}
在查询用户信息时调用此方法即可
@Override
public GraceJSONResult getUserInfo(String userId) {
if (StringUtils.isBlank(userId)) {
return new GraceJSONResult(ResponseStatusEnum.UN_LOGIN);
}
AccountBasicInfoVO accountBasicInfoVO =
new AccountBasicInfoVO();
AppUser user = getUser(userId);
BeanUtils.copyProperties(user, accountBasicInfoVO);
return GraceJSONResult.ok(accountBasicInfoVO);
}
@Override
public GraceJSONResult getAccountInfo(String userId) {
if (StringUtils.isBlank(userId)) {
return GraceJSONResult.errorCustom(ResponseStatusEnum.UN_LOGIN);
}
AppUser appUser = getUser(userId);
AppUserVO appUserVO = new AppUserVO();
BeanUtils.copyProperties(appUser, appUserVO);
return GraceJSONResult.ok(appUserVO);
}
当用户信息进行更新时 只更改了数据库中的信息 而redis中的信息还是以前未修改前的脏数据 所以 更新时要将新数据查询后覆盖到redis中
业务思路:
- 进行用户信息修改操作
- 修改完毕后根据用户id查询到用户 并覆盖到redis中
@Override
@Transactional
public void updateUserInfo(UpdateUserBO updateUserBO) {
AppUser user = new AppUser();
BeanUtils.copyProperties(updateUserBO, user);
user.setActiveStatus(UserStatus.ACTIVE.type);
int resultNum = userMapper.updateById(user);
if (resultNum != 1) {
GraceException.display(ResponseStatusEnum.USER_UPDATE_ERROR);
}
// 更新用户时 将更新后的数据查询出来并覆盖到redis中
AppUser updateUser = this.getUser(updateUserBO.getId());
redisOperator.set(REDIS_USER_CACHE + ":" + updateUserBO.getId(), JsonUtil.objectForJson(updateUser));
}
双写数据不一致的问题
当进行用户信息更新操作时 遇到网络 问题或其他问题而导致只更新了数据库 而未将数据写入redis中 这样就形成了数据不一致的问题
解决方法: 进行更新操作时
- 先将reids中的旧数据删除
- 在修改数据库之后 再将新数据写入redis中
当用户发送多个请求时 旧缓存删除成功但是新数据还未来得及更新到数据库中 读缓存时发现redis中无数据 而想数据库中查询 查到的是未修改的旧数据
解决方法:
- 先将缓存删除
- 将数据库更新
- 线程等待一段时间 再次淘汰缓存数据 用于别的请求请求完成 避免读取脏数据
@Override
@Transactional
public void updateUserInfo(UpdateUserBO updateUserBO) {
// 删除redis数据
redisOperator.del(REDIS_USER_CACHE + ":" + updateUserBO.getId());
AppUser user = new AppUser();
BeanUtils.copyProperties(updateUserBO, user);
user.setActiveStatus(UserStatus.ACTIVE.type);
int resultNum = userMapper.updateById(user);
if (resultNum != 1) {
GraceException.display(ResponseStatusEnum.USER_UPDATE_ERROR);
}
// 更新用户时 将更新后的数据查询出来并覆盖到redis中
AppUser updateUser = this.getUser(updateUserBO.getId());
redisOperator.set(REDIS_USER_CACHE + ":" + updateUserBO.getId(), JsonUtil.objectForJson(updateUser));
try {
Thread.sleep(100);
redisOperator.del(REDIS_USER_CACHE + ":" + updateUserBO.getId());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
虽然道路是曲折的,但前途是光明的。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律