阅读笔记lv.1

阅读笔记

  • sql中各种 count
    • 结论
    • 不同存储引擎计算方式
    • 区别
    • count() 类型
  • 责任链模式
    • 常见场景
    • 例子(闯关游戏)

sql中各种 count

结论

  • innodb
count(*)count(1) > count(主键id) > count(普通索引列) > count(未加索引列)
  • myisam
    有专门字段记录全表的行数,直接读这个字段就好了(innodb则需要一行行去算

  • 如果确实需要获取行数,且可以接受不那么精确的行数(只需要判断大概的量级) 的话,那可以用explain里的rows,这可以满足大部分的监控场景,实现简单

  • 如果要求行数准确 ,可以建个新表,里面专门放表行数的信息

  • 如果对实时性要求比较高 的话,可以将更新行数的sql放入到对应事务里,这样既能满足事务隔离性,还能快速读取到行数信息

  • 如果对实时性要求不高 ,接受一小时或者一天的更新频率,那既可以自己写脚本遍历全表后更新行数信息。也可以将通过监听binlog将数据导入hive,需要数据时直接通过hive计算得出

不同存储引擎计算方式

  • count()方法的目的是计算当前sql语句查询得到的非NULL的行数
    在这里插入图片描述
  • 虽然在server层都叫count()方法,但在不同的存储引擎下,它们的实现方式是有区别的
    • 比如同样是读全表数据
select count(*) from table (where *** )

当数据表小的时候,这是没问题的,但当数据量大的时候,比如未发送的短信到了百万量级 的时候,你就会发现,上面的sql查询时间会变得很长,最后timeout报错,查不出结果了 。

    • 使用 myisam引擎 的数据表里有个记录当前表里有几行数据的字段,直接读这个字段返回就好了,因此速度快得飞起
    • 使用innodb引擎 的数据表,则会选择体积最小的索引树 ,然后通过遍历叶子节点的个数挨个加起来,这样也能得到全表数据

区别

为什么innodb不能像myisam那样实现count()方法

  • 最大的区别在于myisam不支持事务,而innodb支持事务
    而事务,有四层隔离级别,其中默认隔离级别就是可重复读隔离级别(RR)

    • innodb引擎通过MVCC实现了可重复隔离级别 ,事务开启后,多次执行同样的select快照读 ,要能读到同样的数据。
    • 对于两个事务A和B,一开始表假设就2条 数据,那事务A一开始确实是读到2条数据。事务B在这期间插入了1条数据,按道理数据库其实有3条数据了,但由于可重复读的隔离级别,事务A依然还是只能读到2条数据。
    • 因此由于事务隔离级别的存在,不同的事务在同一时间下,看到的表内数据行数是不一致的 ,因此innodb,没办法,也没必要像myisam那样单纯的加个count字段信息在数据表上

count() 类型

count方法的大原则是server层会从innodb存储引擎里读来一行行数据,并且只累计非null的值 。但这个过程,根据count()方法括号内的传参,有略有不同。

  • count(*)
    server层拿到innodb返回的行数据,不对里面的行数据做任何解析和判断 ,默认取出的值肯定都不是null,直接行数+1
  • count(1)
    server层拿到innodb返回的行数据,每行放个1进去,默认不可能为null,直接行数+1.
    • InnoDB 引擎遍历整张表,但不取值。server 层对于返回的每一行,放一个数字“1”进去,判断是不可能为空的,按行累加
  • count(字段)
    count(字段)是不统计,字段值为null的值
    • count(主键 id) 来说,InnoDB 引擎会遍历整张表,把每一行的 id 值都取出来,返回给 server 层。server 层拿到 id 后,判断是不可能为空的,就按行累加
    • count(字段),server要字段,就返回字段,如果字段为空,就不做统计,字段的值过大,都会造成效率低下

      由于指明了要count某个字段,innodb在取数据的时候,会把这个字段解析出来 返回给server层,所以会比count(1)和count(*)多了个解析字段出来的流程

在这里插入图片描述

责任链模式

  • 责任链模式是一种行为设计模式, 允许你将请求沿着处理者链进行发送。收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者。

在这里插入图片描述

常见场景

  1. 多条件的流程判断(如导入文件校验条件较多,且需逐层校验成功的;或类似闯关游戏,必须达到一定分数/条件才能开始下一关)
    导入功能可能【模板方法】更适合
    • 模板方法可以提供大部分相同的【模板】,根据不同的导入场景做小部分调整,实现各自独立的业务,大体上导入功能差不多
    • 一次性实现一个算法的不变部分,并将可变的行为留给子类来实现
    • 各子类中公共的行为被提取出来并集中到一个公共父类中,从而避免代码重复
      在这里插入图片描述
  1. ERP 系统流程审批:总经理、人事经理、项目经理
  2. Java 过滤器的底层实现 Filter

例子(闯关游戏)

  • 假设现在有一个闯关游戏,进入下一关的条件是上一关的分数要高于 xx:

  • 游戏一共 3 个关卡
    进入第二关需要第一关的游戏得分大于等于 80
    进入第三关需要第二关的游戏得分大于等于 90

简易版(多层 if 逐层判断是否满足条件)

//第一关
public class FirstPassHandler {public int handler(){System.out.println("第一关-->FirstPassHandler");return 80;}
}//第二关
public class SecondPassHandler {public int handler(){System.out.println("第二关-->SecondPassHandler");return 90;}
}//第三关
public class ThirdPassHandler {public int handler(){System.out.println("第三关-->ThirdPassHandler,这是最后一关啦");return 95;}
}//客户端
public class HandlerClient {public static void main(String[] args) {FirstPassHandler firstPassHandler = new FirstPassHandler();//第一关SecondPassHandler secondPassHandler = new SecondPassHandler();//第二关ThirdPassHandler thirdPassHandler = new ThirdPassHandler();//第三关int firstScore = firstPassHandler.handler();//第一关的分数大于等于80则进入第二关if(firstScore >= 80){int secondScore = secondPassHandler.handler();//第二关的分数大于等于90则进入第二关if(secondScore >= 90){thirdPassHandler.handler();}}}
}
  • 实际上的 handle() 根据业务来传参及计算分数
  • 缺点
    当关数越多/条件越多时代码会变得很长,无限月读(if 嵌套)
if(1关通过){// 第2关 游戏if(2关通过){// 第3关 游戏if(3关通过){// 第4关 游戏if(4关通过){// 第5关 游戏if(5关通过){// 第6关 游戏if(6关通过){//...}}} }}
}

升级(责任链链表拼接每一关)

  • 可以通过链表将每一关连接起来,形成责任链的方式,第一关通过后是第二关,第二关通过后是第三关… (减少客户端代码过多的 if 嵌套)
public class FirstPassHandler {/*** 第一关的下一关是 第二关*/private SecondPassHandler secondPassHandler;public void setSecondPassHandler(SecondPassHandler secondPassHandler) {this.secondPassHandler = secondPassHandler;}//本关卡游戏得分private int play(){return 80;}public int handler(){System.out.println("第一关-->FirstPassHandler");if(play() >= 80){//分数>=80 并且存在下一关才进入下一关if(this.secondPassHandler != null){return this.secondPassHandler.handler();}}return 80;}
}public class SecondPassHandler {/*** 第二关的下一关是 第三关*/private ThirdPassHandler thirdPassHandler;public void setThirdPassHandler(ThirdPassHandler thirdPassHandler) {this.thirdPassHandler = thirdPassHandler;}//本关卡游戏得分private int play(){return 90;}public int handler(){System.out.println("第二关-->SecondPassHandler");if(play() >= 90){//分数>=90 并且存在下一关才进入下一关if(this.thirdPassHandler != null){return this.thirdPassHandler.handler();}}return 90;}
}public class ThirdPassHandler {//本关卡游戏得分private int play(){return 95;}/*** 这是最后一关,因此没有下一关*/public int handler(){System.out.println("第三关-->ThirdPassHandler,这是最后一关啦");return play();}
}public class HandlerClient {public static void main(String[] args) {FirstPassHandler firstPassHandler = new FirstPassHandler();//第一关SecondPassHandler secondPassHandler = new SecondPassHandler();//第二关ThirdPassHandler thirdPassHandler = new ThirdPassHandler();//第三关firstPassHandler.setSecondPassHandler(secondPassHandler);//第一关的下一关是第二关secondPassHandler.setThirdPassHandler(thirdPassHandler);//第二关的下一关是第三关//说明:因为第三关是最后一关,因此没有下一关//开始调用第一关 每一个关卡是否进入下一关卡 在每个关卡中判断firstPassHandler.handler();}
}
  • 缺点
    从代码中可以看到,每一关的处理逻辑中都有一个 set**PassHandler() 方法,只是参数类型不一样,但是作用其实是一样的,只是用来判断是否有下一关
    每个关卡中都有下一关的成员变量并且是不一样的,形成链很不方便,代码扩展性不行

进化(责任链改造—抽象)

  • 每个关卡中都有下一关的成员变量并且是不一样的,那么我们可以在关卡上抽象出一个父类或者接口,然后每个具体的关卡去继承或者实现,将参数合并成一个,不再需要在各自的 set**PassHandler 中传递不同的参数
  • 责任链设计模式的基本组成
    • 抽象处理者(Handler)角色: 定义一个处理请求的接口,包含抽象处理方法和一个后继连接
    • 具体处理者(Concrete Handler)角色: 实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者
    • 客户类(Client)角色: 创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程
      在这里插入图片描述
public abstract class AbstractHandler {/*** 下一关用当前抽象类来接收*/protected AbstractHandler next;public void setNext(AbstractHandler next) {this.next = next;}public abstract int handler();
}public class FirstPassHandler extends AbstractHandler{private int play(){return 80;}@Overridepublic int handler(){System.out.println("第一关-->FirstPassHandler");int score = play();if(score >= 80){//分数>=80 并且存在下一关才进入下一关if(this.next != null){return this.next.handler();}}return score;}
}public class SecondPassHandler extends AbstractHandler{private int play(){return 90;}public int handler(){System.out.println("第二关-->SecondPassHandler");int score = play();if(score >= 90){//分数>=90 并且存在下一关才进入下一关if(this.next != null){return this.next.handler();}}return score;}
}public class ThirdPassHandler extends AbstractHandler{private int play(){return 95;}public int handler(){System.out.println("第三关-->ThirdPassHandler");int score = play();if(score >= 95){//分数>=95 并且存在下一关才进入下一关if(this.next != null){return this.next.handler();}}return score;}
}public class HandlerClient {public static void main(String[] args) {FirstPassHandler firstPassHandler = new FirstPassHandler();//第一关SecondPassHandler secondPassHandler = new SecondPassHandler();//第二关ThirdPassHandler thirdPassHandler = new ThirdPassHandler();//第三关// 和上面没有更改的客户端代码相比,只有这里的set方法发生变化,其他都是一样的firstPassHandler.setNext(secondPassHandler);//第一关的下一关是第二关secondPassHandler.setNext(thirdPassHandler);//第二关的下一关是第三关//说明:因为第三关是最后一关,因此没有下一关//从第一个关卡开始firstPassHandler.handler();}
}
  • 从代码中可以看到,此次进化引入了一个 抽象处理者,让每一关的具体处理者都继承该类,后续在设置下一关对象的时候就不必各自编写各自的set**PassHandler() 方法,而是直接使用相同的处理方法,只需要编写各自的 handler() 得分方法,进一步简化了代码

终极进化(责任链工厂改造)

public enum GatewayEnum {// handlerId, 拦截者名称,全限定类名,preHandlerId,nextHandlerIdAPI_HANDLER(new GatewayEntity(1, "api接口限流", "cn.dgut.design.chain_of_responsibility.GateWay.impl.ApiLimitGatewayHandler", null, 2)),BLACKLIST_HANDLER(new GatewayEntity(2, "黑名单拦截", "cn.dgut.design.chain_of_responsibility.GateWay.impl.BlacklistGatewayHandler", 1, 3)),SESSION_HANDLER(new GatewayEntity(3, "用户会话拦截", "cn.dgut.design.chain_of_responsibility.GateWay.impl.SessionGatewayHandler", 2, null)),;GatewayEntity gatewayEntity;public GatewayEntity getGatewayEntity() {return gatewayEntity;}GatewayEnum(GatewayEntity gatewayEntity) {this.gatewayEntity = gatewayEntity;}
}public class GatewayEntity {private String name;private String conference;private Integer handlerId;private Integer preHandlerId;private Integer nextHandlerId;
}public interface GatewayDao {/*** 根据 handlerId 获取配置项* @param handlerId* @return*/GatewayEntity getGatewayEntity(Integer handlerId);/*** 获取第一个处理者* @return*/GatewayEntity getFirstGatewayEntity();
}public class GatewayImpl implements GatewayDao {/*** 初始化,将枚举中配置的handler初始化到map中,方便获取*/private static Map<Integer, GatewayEntity> gatewayEntityMap = new HashMap<>();static {GatewayEnum[] values = GatewayEnum.values();for (GatewayEnum value : values) {GatewayEntity gatewayEntity = value.getGatewayEntity();gatewayEntityMap.put(gatewayEntity.getHandlerId(), gatewayEntity);}}@Overridepublic GatewayEntity getGatewayEntity(Integer handlerId) {return gatewayEntityMap.get(handlerId);}@Overridepublic GatewayEntity getFirstGatewayEntity() {for (Map.Entry<Integer, GatewayEntity> entry : gatewayEntityMap.entrySet()) {GatewayEntity value = entry.getValue();//  没有上一个handler的就是第一个if (value.getPreHandlerId() == null) {return value;}}return null;}
}public class GatewayHandlerEnumFactory {private static GatewayDao gatewayDao = new GatewayImpl();// 提供静态方法,获取第一个handlerpublic static GatewayHandler getFirstGatewayHandler() {GatewayEntity firstGatewayEntity = gatewayDao.getFirstGatewayEntity();GatewayHandler firstGatewayHandler = newGatewayHandler(firstGatewayEntity);if (firstGatewayHandler == null) {return null;}GatewayEntity tempGatewayEntity = firstGatewayEntity;Integer nextHandlerId = null;GatewayHandler tempGatewayHandler = firstGatewayHandler;// 迭代遍历所有handler,以及将它们链接起来while ((nextHandlerId = tempGatewayEntity.getNextHandlerId()) != null) {GatewayEntity gatewayEntity = gatewayDao.getGatewayEntity(nextHandlerId);GatewayHandler gatewayHandler = newGatewayHandler(gatewayEntity);tempGatewayHandler.setNext(gatewayHandler);tempGatewayHandler = gatewayHandler;tempGatewayEntity = gatewayEntity;}// 返回第一个handlerreturn firstGatewayHandler;}/*** 反射实体化具体的处理者* @param firstGatewayEntity* @return*/private static GatewayHandler newGatewayHandler(GatewayEntity firstGatewayEntity) {// 获取全限定类名String className = firstGatewayEntity.getConference(); try {// 根据全限定类名,加载并初始化该类,即会初始化该类的静态段Class<?> clazz = Class.forName(className);return (GatewayHandler) clazz.newInstance();} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {e.printStackTrace();}return null;}}public class GetewayClient {public static void main(String[] args) {GetewayHandler firstGetewayHandler = GetewayHandlerEnumFactory.getFirstGetewayHandler();firstGetewayHandler.service();}
}
  • 待深究

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/236759.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

pytorch学习笔记(十)

一、损失函数 举个例子 比如说根据Loss提供的信息知道&#xff0c;解答题太弱了&#xff0c;需要多训练训练这个模块。 Loss作用&#xff1a;1.算实际输出和目标之间的差距 2.为我们更新输出提供一定的依据&#xff08;反向传播&#xff09; 看官方文档 每个输入输出相减取…

手把手教你学会接口自动化系列九-封装调用之后的代码展示

接上篇: 手把手教你学会接口自动化系列八-将url写在配置文件中,封装调用-CSDN博客 下来把之前写的demo开始改造,将所有的url = http://192.168.0.134:8081的部分,替代了 如下: demo的改造 # !/usr/bin/env python# -*- coding: utf-8 -*-# @Time : 2023/05# @Author …

S1-06 消息队列

消息队列 消息队列是一种在多任务操作系统中广泛使用的通信机制。它可以用于不同任务之间的消息传递&#xff0c;从而实现数据共享和协调处理任务之间的顺序。 消息队列通常具有以下基本特点&#xff1a; 消息队列的大小有限&#xff1a;消息队列被设计为一种缓冲区&#xff…

【软件测试】路径覆盖

题目要求&#xff1a; a) 流程图如下&#xff1a; b) Consider test cases ti (n 3) and t2 ( n 5). Although these tour the same prime paths in printPrime(), they dont necessarily find the same faults. Design a simple fault that t2 would be more lik…

Legion R7000 2021(82JW)原装出厂Win10/WIN11系统预装OEM系统镜像

LENOVO联想拯救者R7000 2021款(82JW)笔记本电脑原厂Windows10/11系统 链接&#xff1a;https://pan.baidu.com/s/1m_Ql5qu6tnw62PbpvXB0hQ?pwd6ek4 提取码&#xff1a;6ek4 原装出厂系统自带所有驱动、出厂主题壁纸、系统属性专属联机支持标志、系统属性专属联想的LOGO标…

js:使用canvas画一个半圆

背景 需求需要画一个半圆&#xff0c;或者多半圆&#xff0c;其实一下子就能想到 canvas 中的圆弧&#xff0c;核心使用 context.arc context.arc(x,y,r,sAngle,eAngle,counterclockwise)接下来我们看看示例 例一 <!DOCTYPE html> <html lang"en"> &…

C++八股学习心得.8

1.const知道吗&#xff1f;解释其作用 const 修饰类的成员变量&#xff0c;表示成员常量&#xff0c;不能被修改。 const修饰函数承诺在本函数内部不会修改类内的数据成员&#xff0c;不会调用其它非 const 成员函数。 如果 const 构成函数重载&#xff0c;const 对象只能调…

Canopen学习笔记——sync同步报文增加数据域(同步计数器)

1.Canfestival同步报文sync的设置 在OD表中的配置如下&#xff1a; 如果0x1006索引的同步报文循环周期时间设置为0则禁用同步报文&#xff0c;这里要注意的就是&#xff0c;上面第一张图也提到了&#xff0c;时间单位是us。第二张图&#xff0c;我的0x1006就设置为0xF4240,也就…

Docker与微服务实战(高级篇)- 【下】

Docker与微服务实战&#xff08;高级篇&#xff09;- 【下】 八、Docker轻量级可视化工具Portainer8.1.可视化工具Portainer简介8.2.安装Portainer8.2.1.官网8.2.2.docker命令安装8.2.2.1.搜索portainer镜像8.2.2.2.拉取portainer镜像8.2.2.3.启动portainer容器 8.2.3.第一次登…

高通平台开发系列讲解(USB篇)adb function代码分析

文章目录 一、FFS相关动态打印二、代码入口三、ffs_alloc_inst四、ep0、ep1&ep2的注册五、读写过程沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本文主要介绍高通平台USB adb function代码f_fs.c。 一、FFS相关动态打印 目录:msm-4.14/drivers/usb/gadget/fun…

Git新手?这篇文章带你飞!基础操作一网打尽!

推荐阅读 智能化校园&#xff1a;深入探讨云端管理系统设计与实现&#xff08;一&#xff09; 智能化校园&#xff1a;深入探讨云端管理系统设计与实现&#xff08;二&#xff09; 文章目录 推荐阅读Git初识Git啥是版本控制系统&#xff1f;&#xff1f;集中式VS分布式 git使用…

88.乐理基础-记号篇-反复记号(二)D.C.、D.S.、Fine、Coda

内容参考于&#xff1a;三分钟音乐社 上一个内容&#xff1a;87.乐理基础-记号篇-反复记号&#xff08;一&#xff09;反复、跳房子-CSDN博客 下图红色左括号框起来的东西&#xff0c;它们都相对比较抽象一点&#xff0c;这几个词都是意大利语 首先D.C.这个标记&#xff0c;然…

基于DNA的密码学和隐写术综述

摘要 本文全面调研了不同的脱氧核糖核酸(DNA)-基于密码学和隐写术技术。基于DNA的密码学是一个新兴领域,利用DNA分子的大规模并行性和巨大的存储容量来编码和解码信息。近年来,由于其相对传统密码学方法的潜在优势,如高存储容量、低错误率和对环境因素的抗性,该领域引起…

.NET core 中的Kestrel 服务器

什么是Kestrel&#xff1f; Kestrel 是一个跨平台的Web服务器&#xff0c;会默认在ASP.NET Core 项目模板中对其进行配置。未使用 IIS 托管时&#xff0c;ASP.NET Core 项目模板默认使用 Kestrel。 Kestrel 的功能包括&#xff1a; 跨平台&#xff1a;Kestrel 是可在 Window…

蓝桥杯基础知识3 memset()

蓝桥杯基础知识3 memset() #include <bits/stdc.h> using namespace std;int main(){int a[5]; //随机数for(int i 0;i < 5; i)cout << a[i] << \n;cout << \n;memset(a, 0, sizeof a); //0for(int i 0;i < 5; i)cout << a[i] << …

最新ThinkPHP版本实现证书查询系统,实现批量数据导入,自动生成电子证书

前提&#xff1a;朋友弄了一个培训机构&#xff0c;培训考试合格后&#xff0c;给发证书&#xff0c;需要一个证书查询系统。委托我给弄一个&#xff0c;花了几个晚上给写的证书查询系统。 实现功能&#xff1a; 前端按照姓名手机号码进行证书查询证书信息展示证书展示&#x…

kotlin运行

1.使用android studio 由于我本身是做android的&#xff0c;android studio本身有内置kotlin的插件。但若只是想跑kotlin的程序&#xff0c;并不像和android程序绑在一起&#xff0c;可以创建一个kt文件&#xff0c;在里面写一个main函数&#xff0c;就可以直接运行kotlin程序…

2024.1.13每日一题

LeetCode 2182.构造限制重复的字符串 2182. 构造限制重复的字符串 - 力扣&#xff08;LeetCode&#xff09; 题目描述 给你一个字符串 s 和一个整数 repeatLimit &#xff0c;用 s 中的字符构造一个新字符串 repeatLimitedString &#xff0c;使任何字母 连续 出现的次数都…

[足式机器人]Part2 Dr. CAN学习笔记 - Ch02动态系统建模与分析

本文仅供学习使用 本文参考&#xff1a; B站&#xff1a;DR_CAN Dr. CAN学习笔记 - Ch02动态系统建模与分析 1. 课程介绍2. 电路系统建模、基尔霍夫定律3. 流体系统建模4. 拉普拉斯变换&#xff08;Laplace&#xff09;传递函数、微分方程4.1 Laplace Transform 拉式变换4.2 收…

【python】07.字符串和常用数据结构

字符串和常用数据结构 使用字符串 第二次世界大战促使了现代电子计算机的诞生&#xff0c;最初计算机被应用于导弹弹道的计算&#xff0c;而在计算机诞生后的很多年时间里&#xff0c;计算机处理的信息基本上都是数值型的信息。世界上的第一台电子计算机叫ENIAC&#xff08;电…