网站开发后端指什么,网页设计实训班,安庆市网站建设,wordpress author id高并发如何实现单用户信息查询接口
故事情节
产品#xff1a;小李#xff0c;有个单用户信息查询的功能#xff0c;需要你实现一下小李#xff1a;这还不简单#xff0c;两分钟我给你实现两分钟过去…小李#xff1a;欧克了#xff0c;部署上线了运维#xff1a;哪个…高并发如何实现单用户信息查询接口
故事情节
产品小李有个单用户信息查询的功能需要你实现一下小李这还不简单两分钟我给你实现两分钟过去…小李欧克了部署上线了运维哪个傻蛋写的接口导致MySQL宕机了小李一愣他写的接口明明没有报错啊这是怎么回事呢产品小李赶紧给我排查出来否则这个月的奖金一分都没有小李这这这我不知道什么问题啊小李纳闷中思来思去不知道什么问题如何解决…小李老黄只能求你出马了这个月我的奖金全部都给你老黄听到小李的请求他微微一笑答应了下来老黄么得问题了老黄耐心地指导小李修复了这个错误并对代码进行了优化和完善小李听得认真心里暗自发誓要吸取教训以后在工作中更加严谨细致。而这次经历也让他对老黄产生了更深的敬意和信任最终小李成功排查并解决了问题产品顺利上线运行。产品部门的领导对他的表现给予了肯定和赞赏而他也因为自己的努力和进步获得了全额的奖金
小李写的代码
Service层 直接查询MySQL返回数据 public UserQueryRespDTO queryUserByUserId(Long userId) {LambdaQueryWrapperUserDO queryWrapper Wrappers.lambdaQuery(UserDO.class).eq(UserDO::getUserId, userId);ListUserDO userDOList userMapper.selectList(queryWrapper);UserDO userDO CollUtil.isNotEmpty(userDOList) ? userDOList.get(0) : null;UserQueryRespDTO userQueryRespDTO new UserQueryRespDTO();BeanUtil.convert(userDO, userQueryRespDTO);return userQueryRespDTO;
}流程图
http 请求直接打到 MySQL 数据库不宕机才怪嘞
老黄写的代码
Service层
先读取 Redis 缓存数据存在直接返回用户数据不存在读取 MySQL 数据库加上双重判定锁减轻获得分布式锁后线程访问数据库压力读取到 MySQL 数据缓存到 Redis 并且返回读取数据为NULL缓存空对象到 Redis 中并设置一个较短的过期时间防止缓存穿透
public UserQueryRespDTO queryUserByUserId(Long userId) {UserDO userDO distributedCache.safeGet(USER_INFO_KEY userId,UserDO.class,() - {LambdaQueryWrapperUserDO queryWrapper Wrappers.lambdaQuery(UserDO.class).eq(UserDO::getUserId, userId);ListUserDO userDOList userMapper.selectList(queryWrapper);return CollUtil.isNotEmpty(userDOList) ? userDOList.get(0) : null;},30,TimeUnit.MINUTES,null,null,key - {// 缓存空对象解决缓存穿透。也可以使用布隆过滤器。distributedCache.put(key, new UserDO(), 5, TimeUnit.MINUTES);});UserQueryRespDTO userQueryRespDTO new UserQueryRespDTO();BeanUtil.convert(userDO, userQueryRespDTO);return userQueryRespDTO;
}第二行distributedCache.safeGet方法
public T T safeGet(String key, ClassT clazz, CacheLoaderT cacheLoader, long timeout, TimeUnit timeUnit,RBloomFilterString bloomFilter, CacheGetFilterString cacheGetFilter, CacheGetIfAbsentString cacheGetIfAbsent) {T result get(key, clazz);// 缓存结果不等于空或空字符串直接返回通过函数判断是否返回空为了适配布隆过滤器无法删除的场景两者都不成立判断布隆过滤器是否存在不存在返回空if (!CacheUtil.isNullOrBlank(result)|| Optional.ofNullable(cacheGetFilter).map(each - each.filter(key)).orElse(false)|| Optional.ofNullable(bloomFilter).map(each - !each.contains(key)).orElse(false)) {return result;}RLock lock redissonClient.getLock(SAFE_GET_DISTRIBUTED_LOCK_KEY_PREFIX key);lock.lock();try {// 双重判定锁减轻获得分布式锁后线程访问数据库压力if (CacheUtil.isNullOrBlank(result get(key, clazz))) {// 如果访问 cacheLoader 加载数据为空执行后置函数操作if (CacheUtil.isNullOrBlank(result loadAndSet(key, cacheLoader, timeout, timeUnit, true, bloomFilter))) {Optional.ofNullable(cacheGetIfAbsent).ifPresent(each - each.execute(key));}}} finally {lock.unlock();}return result;
}流程图