范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

生产环境首页数据查询速度怎么优化都慢,原因竟然是这个小细节

  背景
  最近,小王很苦恼,他说有一个项目的首页数据加载很慢,他说数据库也加了索引,而且也使用 Redis 对热点数据做了缓存,但是不管怎么优化,数据加载速度还是提升不了。
  然后我检查了小王的代码,看到如下一行代码,我说你写这样的代码,你是想被辞退吗?public List getGoodsList() {     // 省略一些代码     List goods = Optional.ofNullable(getFromCache()).orElse(getFromDB());     // 省略一些代码     return goods; }
  问题分析
  首先,Optional 这个工具类是一个容器对象,可包含亦可不包含一个非空值。它是我们开发中可作为一种判空的优雅解决方法。对于下面这行代码,意思是如果 x 的值不为 null,则返回 x,否则返回 y。Optional.ofNullable(x).orElse(y);
  那按这样的逻辑,小王写的代码那不是应该没问题吗?如果你这样想,那我们运行如下代码看结果。package com.chenpi;  import java.util.ArrayList; import java.util.List; import java.util.Optional;  /**  * @Description  * @Author Mr.nobody  * @Date 2021/06/14  * @Version 1.0  */ public class Demo {     public static void main(String[] args) {         List goodsList = new Demo().getGoodsList();     }      public List getGoodsList() {         // 省略一些代码         List goods = Optional.ofNullable(getFromCache()).orElse(getFromDB());         // 省略一些代码         return goods;     }      private List getFromCache() {         System.out.println("getFromCache");         List list = new ArrayList<>();         list.add(new Goods("手机"));         list.add(new Goods("电脑"));         return list;     }      private List getFromDB() {         System.out.println("getFromDB");         List list = new ArrayList<>();         list.add(new Goods("手机"));         list.add(new Goods("电脑"));         return list;     } }
  运行结果getFromCache getFromDB
  结果发现,即使从缓存已经获取到非空的数据了,但是还是执行了数据库查询操作。所以相当于 Redis 缓存和持久层数据库都进行了查询操作,而且如果从持久层数查询到的数据还要进行费时的计算处理才是最终结果,那可想,即使你怎么优化速度还是提升不了。
  打开源码,orElse 方法参数是传入一个值,注意这个值是已经计算好的了,然后再判断 Optional 容器内的对象是否为空,再决定返回哪个对象值。public T orElse(T other) {     return value != null ? value : other; }
  其实,我们应该使用另外一个方法 orElseGet ,就不会出现这样的问题了,源码如下:public T orElseGet(Supplier<? extends T> other) {     return value != null ? value : other.get(); }
  这里使用到了 Supplier 这个函数接口,里面只有一个无参方法,这个方法的作用就是返回一个值。源码如下:@FunctionalInterface public interface Supplier {      /**      * Gets a result.      *      * @return a result      */     T get(); }
  这就是 JDK8 的函数式编程了,你可以理解为我们可以把一个函数当作一个参数去传递。从 orElseGet 方法看出,只有 Optional 容器内的对象为空的情况下,才会去调用 Supplier 对象的 get 方法。
  所以对于小王的代码,应该这样处理,就不会出现缓存有数据还去查询持久层数据的情况了。达到了延迟加载的效果。List goods = Optional.ofNullable(getFromCache()).orElseGet(this::getFromDB);
  运行结果getFromCache
  其他案例分析
  其实 Supplier 这个函数式接口如果用得巧,那优点还是挺多的。例如我们可以发现 JDK 自带的日志 Logger 类中有某些方法就使用到了 Supplier 接口。这样设计有什么好处呢?后面分析细讲。public void log(Level level, Supplier msgSupplier) {     if (!isLoggable(level)) {         return;     }     LogRecord lr = new LogRecord(level, msgSupplier.get());     doLog(lr); }
  我们实际项目中应该是很少使用输出 debug 调试日志的,但是如果某天出现了 bug,我们想输出必要的日志信息用于排除问题,所以我们在程序中可能会编写这样的 debug 调试日志:log.debug("打印调试日志:{}", JSON.toJSONString(object));
  但是在生产环境中,为了性能考虑,一般只开启 info 级别,过滤掉 debug 级别的日志。所以上述的 debug 调试日志就不会被输出,但是如果你程序充斥着大量这样的代码的话,有可能你的程序性能会下降。
  我们做一个试验,程序只开启 info 日志级别,然后运行程序,看如下的代码的运行结果如何:public class Demo {      public static void main(String[] args) {         Goods goods = new Goods();         goods.setName("手机");         log.debug("打印调试日志:{}", goods.toString());     } }  class Goods {      private String name;      @Override     public String toString() {         System.out.println("toString 方法被调用了...");         return "Goods{" + "name="" + name + """ + "}";     } }
  运行结果toString 方法被调用了...
  可能有人会说这没问题,debug 调试信息确实没有打印出来了。但是你是否发现 toString 方法被调用了,如果不是一个简单的 toString 方法,而是一个非常耗时的执行方法,那情况就不一样了。我之前看到有人将一个大量数据的数组打印出来,满屏满屏的调试数据,很可怕。
  下面我们演示程序只开启 info 日志级别,但是用 debug 级别的日志调试语句打印一个10000容量的数组数据:public class Demo {      public static void main(String[] args) {          int size = 10000;         List goodsList = new ArrayList<>(size);         for (int i = 0; i < size; i++) {             Goods goods = new Goods();             goods.setName("手机" + i);             goodsList.add(goods);         }         long startTime = System.currentTimeMillis();         log.debug("打印调试日志:{}", JSON.toJSONString(goodsList));         System.out.println("spend time:" + (System.currentTimeMillis() - startTime));     } }  class Goods {     private String name; }
  运行结果如下,因为是开启 info 级别,不会打印 debug 级别的日志,但是这行语句却消耗了353毫秒。如果数组中对象的属性不是一个,而是几十个的话,那消耗的时间就更多了。spend time:353
  显然,不管是否开启 debug 级别, JSON.toJSONString(goodsList) 这个方法都被执行了。显然是不合理的,很容易造成性能问题。有一种解决方法,就是先判断是否开启了 debug 级别,这也是很多框架使用到的一种解决方案。if (log.isDebugEnabled()) {     log.debug("打印调试日志:{}", JSON.toJSONString(goodsList)); }
  再运行程序,发现效果是显而易见的,耗时变成0毫秒了。spend time:0
  这时有人想说,那我们的程序就会像判空那样充斥着大量的 if (log.isDebugEnabled()) 语句了。这时,我们可以借助 Supplier 的延迟加载特性,只有使用时才去计算真正需要的数据,其中某个日志打印方法定义如下:public void log(Level level, Supplier msgSupplier) {     if (!isLoggable(level)) {         return;     }     LogRecord lr = new LogRecord(level, msgSupplier.get());     doLog(lr); }
  其实,有时没必要刻意去使用某个功能点,而是应该要结合实际情况作出合适自己项目的方案,这样才能发挥最大用处。因为如果你对这个功能点了解不深,使用不当,那就适得其反,得不偿失。
  作者:陈皮的JavaLib
  链接:https://juejin.cn/post/6973845465867485192

2K270Hz能带怎样的游戏体验?宏碁暗影骑士威体验电竞的繁荣,让更多的玩家加入到竞技类游戏的阵营。与休闲类游戏相比,决胜分毫之间的竞技类游戏对玩家有着更高的要求,无论是自身技术,还是外在的装备。工欲善其事,必先利其器放之四海皆准,暖气虽好,干燥难熬!想舒舒服服过冬,不会选加湿器怎么行时间过得真快,转眼间北方将陆续入冬,开始进入供暖期。虽然供暖以后家里变得温暖,但随之而来的突出问题就是家里变得空前干燥。天津还没开始供暖室内湿度就已低至40左右,供暖之后就是没有最清华教授用57小时讲完的Python,整整598集,拿走不谢兄弟!毫无套路!!!福利分享1本套视频一共458集,本套视频共分4季第一季Python基础。第二季。Python深入和扩展第三季网络编程多线程扩展库第四季算法Python源码函数式拜普会敲定后,波兰外长突然访华,还对中欧投资协定表态了?图为拜登与普京如今美国与俄罗斯的关系仍然很长,但最近已经出现了缓和的迹象,最近美国总统拜登与俄罗斯总统普京达成了一致,双方将选定时间进行面对面的会谈,而就在拜普会被敲定之后,欧洲一清华教授用57小时讲完的Python,整整598集,拿走不谢兄弟!毫无套路!!!福利分享1本套视频一共458集,本套视频共分4季第一季Python基础。第二季。Python深入和扩展第三季网络编程多线程扩展库第四季算法Python源码函数式清华教授用57小时讲完的Python,整整598集,拿走不谢兄弟!毫无套路!!!福利分享1本套视频一共458集,本套视频共分4季第一季Python基础。第二季。Python深入和扩展第三季网络编程多线程扩展库第四季算法Python源码函数式带娃从北飞到南畅玩长隆,全靠地平线8号大旅行家拉杆箱一路随行有了娃以后,总想带娃到处走走,看看外面的世界。娃小的时候,主要以短途休闲游为主,量力而行,怎么舒服怎么放松怎么来随着娃一天天长大,自我意识逐渐增强,领悟能力理解能力有了明显提升,好开了这么久的车,孩子的安全座椅你选得对吗?随着生活水平的提高,汽车以迅雷不及掩耳盗铃之势进入我们的生活,汽车之于我们的意义不再是单纯的交通工具,而是我们生活的一部分,日常通勤周末的短途出行,乃至长假的举家出游,汽车都发挥着大功率能盲插,倍思100W氮化镓快充充电器了解一下?苹果以环保之名取消随机的充电器,小米也以比较友好的方式跟进,虽然不再附带充电器我们比较不爽,但充电器越来越多也是不争的事实。随着数码产品在我们生活中的比重越来越高,大家都不约而同地幻13全能本领衔ROG多款重磅新品发布2021年1月13日,ROG2021新品发布会,ROG全产品线新品重磅发布。ROG一直秉承以玩家为核心的品牌理念,旗下产品始终坚持毫不妥协的电竞信仰,不断推陈出新,不仅为玩家提供极NAS折腾之路入手这些配件,让群晖DS920用起来更得劲转眼入手群晖DS920已经小两个月了,用起来还是蛮爽的,数据资料即时备份,省时省力,安全许多日常工作不用随身带U盘硬盘了,轻松许多影音娱乐多设备共享,随时访问,快乐许多。而且用的多
2019款别克君威20T精英型改装,花小钱办大事,外观内饰大提升车就像自己的老婆,总想把它打扮的漂漂亮亮,开出去有面子,自己用起来也更舒心。我是2019款别克君威20T精英型车主,提车已经两年多了,目前行驶里程接近4万公里,当时选择别克君威的原极致减重一体式车身本田发布CBR1000RRR全新专利图HONDA在2019年推出CBR1000RRR之后,原先期望这台三倍R能在WSBK赛场上展获佳绩,可惜的是CBR1000RRR未能如预期在赛场上翻盘,HONDA也在不久前传出可能推洛杉矶奥组委发布2028洛杉矶夏季奥运会与残奥会会徽第34届夏季奥林匹克运动会,又称2028年洛杉矶奥运会,这是继1932年洛杉矶奥运会和1984年洛杉矶奥运会后,洛杉矶将第三次举办夏季奥运会。早些时候,洛杉矶2028奥运会组委会发纹身护理产品StoriesampampampInk视觉形象升级StoriesInk是一款屡获殊荣的纹身后护理产品,采用专业成分配制而成,可防止纹身褪色,并改善纹身皮肤的外观和手感。该品牌创办于2017年,由英国利兹RobotFood设计公司孵两性健康用品Champ视觉形象设计Champ于2020年推出,是一个专为男性提供优质标签清晰的两性健康用品品牌。该品牌目前提供两种避孕套和两种润滑液,除了提供优质产品外,其主要目标是消除消费者在零售场所购买避孕套的英特尔公司Intel视觉形象升级英特尔(Intel)是美国一家以研制CPU为主的公司,同时也是全球最大的个人计算机零件和CPU制造商,它成立于1968年,总部位于美国加州,工程技术部和销售部以及6个芯片制造工厂位益生菌苏打水HUZZAH视觉形象设计近日,摩森康胜公司在美国推出了其首批非酒精类饮品,HUZZAH低热量益生菌苏打水,是一种带有帮助维持肠道健康益生菌的调味苏打水。该产品下设三种口味,草莓芙蓉多汁梨和树莓柠檬。今年早小型酿酒厂EastLondonLiquorCompany视觉形象升级EastLondonLiquorCompany成立于2014年,是一家位于英国伦敦哈克尼内区的小型酿酒厂,生产杜松子酒伏特加酒朗姆酒和威士忌酒。早些时候,该酿酒厂推出了六种罐装产品小型连锁休闲餐厅FieldsGoodChicken视觉形象升级FieldsGoodChicken成立于2014年,是一家小型连锁休闲餐厅,专注于烤鸡和健康舒适的食品类配菜。由FieldFailing创办,他曾经是一名职业自行车运动员,也是一名运动鞋商店Footshop视觉形象升级Footshop成立于2011年,是欧洲最受欢迎的运动鞋商店之一,也是捷克和斯洛伐克市场的领导者,总部设在布拉格。专注于各大品牌的时尚运动鞋,在某些情况下甚至获得了独家发行权。本月澳大利亚活动影像中心ACMI视觉形象升级澳大利亚活动影像中心(ACMI)拥有一张精彩无比的年度日程表,墨尔本最出色最受欢迎的电影节都会在这里举办,同时它也是在澳大利亚本土和国际上都享有盛名的电影院。2019年5月,ACM