缓存设计
参考文献
300分钟吃透分布式缓存
七大缓存经典问题
缓存和数据库一致性问题,看这篇就够了
七大缓存经典问题
缓存穿透(一穿到底)
原因分析
缓存穿透存在的原因:用户请求的数据在缓存中和数据库中都不存在,不断发起这样的请求,给数据库带来巨大压力
如用户访问的是一个不存在的 key,查 DB 返回空(即一个 NULL),那就不会把这个空写回 cache.那以后不管查询多少次这个不存在的 key,都会Cache Miss,都会查询 DB.整个系统就会退化成一个 “前端 + DB“的系统,由于 DB 的吞吐只在Cache 的 1%~2% 以下,如果有特殊访客,大量访问这些不存在的 key,就会导致系统的性能严重退化,影响正常用户的访问.
缓存穿透会发⽣在什么时候呢?⼀般来说,有两种情况
业务层误操作:缓存中的数据和数据库中的数据被误删除了,所以缓存和数据库中都没有数据;
恶意攻击:专⻔访问数据库中没有的数据。
处理办法
验证拦截
接口层进行校验拦截,对于一些可预知的非法参数进行拦截,如查询ID字段,传入的值为负值的情况;
回种空值
查询这些不存在的数据时 ...
工具-IDEA问题
参考文献
Error running 'Application': Command line is too long. Shorten command line for Application or also for Spring Boot default configuration.
解决办法:
在IDEA的.idea/workspace.xml文件的<component name="PropertiesComponent">标签下加上
1<property name="dynamic.classpath" value="true" />
IDEA中的war和war exploded的区别
war模式: 将Web工程以war包的形式上传到服务器;
war模式先打成war包,然后发布到Tomcat的ROOT下,使用选择这个后,在看一下Tomcat的ROOT文件夹下是刚打成的项目;
war exploded模式: 将Web工程以当前文件夹的位置关系上传到服务器;
war exp ...
MySQL(九)-索引(二)
参考文献
高性能MySQL(第三版)
极客时间–MySQL实战45讲
数据库索引设计与优化
表和索引结构
索引页和表页
表和索引行都被存储在页中.页的大小仅仅决定了一个页可以存储多少个索引行,表行,以及一共需要多少个页来存储表或者索引.
当表和索引被加载或重组时,每个页都会预留出一定比例的空闲空间,以满足向其添加新的表行或索引行的需求.
缓冲池和I/O活动都是基于页的.例如一次将一个完整的页读取到缓冲池.这意味着一次I/O会读入多条记录到缓冲池,而不仅仅是一条.
索引行
索引行在评估访问路径的时候是一个非常拥有的概念.
对于唯一索引,一个索引行等同于叶子页中的一个索引条目.字段的值从表中复制到索引上,并加上一个指向表中记录的指针.通常,表页的编号是这个指针的组成部分.
对于非唯一索引,一个特定的索引值对应的索引行一个被想象成独立的索引条目,每一个都含有相同的值,但是却有不同的指针.大多数情况下,非唯一索引的实际存储方式是一个值后带着多个指针.
索引结构
非叶子页通常包含着一个键值,以及一个指向下一层级的指针,该键值是下一层级页中的最大键值.
表行
每一个索 ...
Java基础-序列化
参考文献
面试官:Java序列化为什么要实现Serializable接口?我懵了
什么是序列化
序列化: Java中的序列化机制能够将一个实例化对象信息写入到一个字节流中(只序列号对象的属性值,而不会去序列化方法),序列化后的对象可用于网络传输,或者持久化到数据库,磁盘中.
反序列化: 需要对象的时候,在通过字节流中的信息来重构一个相同的对象.
Java中具体实现
Java中要使一个类可以序列化,实现java.io.Serializable接口是最简单的.
1234public class User implements Serializable { private static final long serialVersionUID = 1L;}
123456789@Datapublic class User implements Serializable { private static final long serialVersionUID = 1L; private String name; private S ...
Redis-单线程模型
参考文献
了解redis的单线程模型工作原理?一篇文章就够了
REDIS 单线程模型介绍
redis单线程模型
3w字深度好文|Redis面试全攻略,读完这个就可以和面试官大战几个回合了
极客时间专栏: Redis核心技术与实战
Redis单线程
Redis是单线程,主要是指Redis的网络IO和键值对读写是由一个线程来完成的,这也是Redis对外提供键值存储服务的主要流程.但Redis的其他功能,比如持久化、异步删除、集群数据同步等,其实是由额外的线程执行的.
Redis 为什么使用单线程?
从性能角度来看
多线程的开销
多线程编程模式面临的共享资源的并发访问控制问题.
并发访问控制一直是多线程开发中的一个难点问题,如果没有精细的设计,比如说,只是简单地采用一个粗粒度互斥锁,就会出现不理想的结果:即使增加了线程,大部分线程也在等待获取访问共享资源的互斥锁,并行变串行,系统吞吐率并没有随着线程的增加而增加.
而且,采用多线程开发一般会引入同步原语来保护共享资源的并发访问,这也会降低系统代码的易调试性和可维护性.为了避免这些问题,Redis直接采用了单线程模式.
单 ...
MySQL(九)-索引(一)
参考文献
高性能MySQL(第三版)
极客时间–MySQL实战45讲
数据库索引设计与优化
MySQL 优化之 index merge(索引合并)
索引
概念
关键字与数据的映射关系称为索引(包含关键字和对应的记录在磁盘中的地址).关键字是从数据当中提取的用于标识、检索数据的特定内容.
索引的出现是为了提高查询的效率;
索引用来快速地寻找那些具有特定值的记录.如果没有索引,一般来说执行查询时遍历整张表.
索引的原理很简单,就是把无序的数据变成有序的查询
把创建了索引的列的内容进行排序
对排序结果生成倒排表
在倒排表内容上拼上数据地址链
在查询的时候,先拿到倒排表内容,再取出数据地址链,从而拿到具体数据
索引检索为什么快?
关键字相对于数据本身,数据量小
关键字是有序的,二分查找可快速确定位置
索引操作
创建索引
在创建表的时候对字段进行指定索引
12345678CREATE TABLE user_index ( id INT auto_increment PRIMARY KEY, first_name VARCHAR ( 16 ), last_name VARC ...
SpringMVC-基础
参考文献
【对线面试官】SpringMVC
手码两万余字,SpringMVC 包教包会
SpringMVC中的组件
DispatcherServlet:前端控制器
用户请求到达前端控制器,它就相当于MVC模式中的C,DispatcherServlet 是整个流程控制的中心,相当于是 SpringMVC 的大脑,由它调用其它组件处理用户的请求,DispatcherServlet 的存在降低了组件之间的耦合性。
HandlerMapping:处理器映射器
HandlerMapping 负责根据用户请求找到 Handler 即处理器(也就是我们所说的 Controller),SpringMVC 提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等,在实际开发中,我们常用的方式是注解方式。
Handler:处理器
Handler 是继 DispatcherServlet 前端控制器的后端控制器,在DispatcherServlet 的控制下 Handler 对具体的用户请求进行处理。由于 Handler 涉及到具体的用户业务请求,所以一般情况需 ...
Java基础-反射&&动态代理
参考文献
java动态代理实现与原理详细分析
Trail: The Reflection API
Spring CGLIB 动态代理子类导致的注解丢失
反射
获取Class对象的四种方式
知道具体类的情况下可以使用:
1Class klass = Person.class;
通过 Class.forName()传入类的全路径获取:
1Class klass = Class.forName("cn.holelin.Person");
通过对象实例instance.getClass()获取:
12Person o = new Person();Class klass = o.getClass();
通过类加载器xxxClassLoader.loadClass()传入类路径获取:
1ClassLoader.getSystemClassLoader().loadClass("cn.holelin.Person");
通过类加载器获取 Class 对象不会进行初始化,意味着不进行包括初始化等一系列步骤,静态代码块和静态对象不会得到执 ...
JavaNIO-基础知识点
参考文献
【对线面试官】 Java NIO
Reading a File with Channels and Buffers
Netty权威指南 第二版
黑马-Netty课程
Java NIO浅析
BIO NIO和AIO
BIO、NIO和AIO是Java中用于网络编程的三种不同的I/O模型,它们之间的区别主要体现在对IO操作的处理方式和API设计上.以下是它们的区别:
BIO(Blocking I/O)阻塞I/O
同步阻塞:每个连接都需要一个独立的线程来处理,因此连接数受限于服务器的性能.
通信是同步的,即代码阻塞在输入流(InputStream)和输出流(OutputStream)上等待I/O完成.
只有阻塞模式,无法发挥多路复用的优势.
在I/O通信线程和业务处理线程中使用同一个线程池,无法发挥多核CPU的优势.
NIO(Non-Blocking I/O)非阻塞I/O
异步非阻塞:NIO可以使用单线程处理多个连接(轮询器Selector),因此可以支持更多的连接.
通过Selector实现了多路复用,同时可以采取异步非阻塞模式,即不用等待I/O操作的完成,可以通过回 ...
Java基础-泛型
参考文献
【对线面试官】今天来聊聊Java泛型
Java 基础 - 泛型机制详解
泛型
Java泛型这个特性是从JDK 1.5才开始加入的,因此为了兼容之前的版本,Java泛型的实现采取了“伪泛型”的策略,即Java在语法上支持泛型,但是在编译阶段会进行所谓的“类型擦除”(Type Erasure),将所有的泛型表示(尖括号中的内容)都替换为具体的类型(其对应的原生态类型),就像完全没有泛型一样.
泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型).也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法.
引入泛型的意义在于:
适用于多种数据类型执行相同的代码(代码复用)
泛型类
123456789public class Test<T>{ private T var ; public T getVar(){ return var ; ...