2022 Java 知识点总结
创始人
2024-04-02 07:18:38

2022 Java知识点总结

  • Java Code
    • 类加载
      • 类加载机制
      • 双亲委派机制
      • 类的初始化
    • 反射
      • 反射的实现方式和原理
    • 集合
      • String, Stringbuilder, Stringbuffer区别
      • HashMap原理(底层数据结构)
      • HashMap存数据过程
      • CurrentHashMap原理
      • CurrentHashMap存数据的过程
  • 多线程
    • 线程的实现方式
    • runnable和callable的区别?
    • 线程中wait()和sleep()方法有什么区别?
    • 线程池的几个参数介绍,常用队列以及线程池中拒绝策略?
    • 创建线程池的几种方式
    • synchronized的锁升级原理
    • 什么是死锁,如何避免死锁
  • Stream 流
    • Stream注意点?
    • Stream并行流?并行流的原理
    • 创建Stream的方式
    • Stream的常用方法?
  • SpringBoot
    • springboot启动流程
  • Redis
    • redis高可用的方案?
    • 主从复制原理以及优缺点
    • 哨兵模式原理以及优缺点
    • 集群模式原理、分片算法、优缺点?
    • 缓存穿透、缓存雪崩?如何避免此类问题
    • 缓存的淘汰策略以及Redis中的淘汰策略
  • MySQL数据库
    • 索引失效原因

Java Code

类加载

类加载机制

类的加载过程:Java虚拟机把描述类的数据把.class字节码文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Class对象。类的生命周期包括:加载,验证,准备,解析,初始化,使用,卸载。按顺序开始,而不是按顺序进行或完成,因为这些阶段通常都是互相交叉地混合进行的,通常在一个阶段执行的过程中调用或激活另一个阶段。

双亲委派机制

保证类加载流程的安全性,才使用的双亲委派?
当一个类加载器收到了类加载的请求的时候,他不会直接去加载指定的类,而是把这个请求委托给自己的父加载器去加载。 只有父加载器无法加载这个类的时候,才会由当前这个加载器来负责类的加载。自定义Class Loader ->Appilication Class loader -> Extension Classloader ->Bootstrap ClassLoader
违例:JDBC–Context Classloader
tomcat 为每个 App 创建一个 Loader,里面保存着此 WebApp 的 ClassLoader。需要加载 WebApp 下的类时,就取出 ClassLoader 来使用

类的初始化

时机:1.new对象 2.反射调用对象 3.调用类的静态方法4.读写类的静态变量5.初始化某类是他的直接父类还未初始化则会初始化其父类6.启动时会初始化main()方法所在启动类。 准备阶段,虚拟机会将类变量(static 修饰的变量)分配内存并设置零值。
在类初始化阶段,执行类构造器 () 方法。 类初始化方法有如下特点:
编译器会在将 .java 文件编译成 .class 文件时,收集所有类初始化代码和 static {} 域的代码,收集在一起成为 () 方法;
子类初始化时会首先调用父类的 () 方法;
JVM 会保证 () 方法的线程安全,保证同一时间只有一个线程执行。

反射

反射的实现方式和原理

反射是一种运行时获取和修改对象数据的能力。1.Class.forname(“全限定名”) 2.xx.getClass() 3.String.class 原理:Method类的invoke方法,获取一个MethodAccessor对象ma【此时会check是否已有现成的ma,有就返回,没有就用ReflectionFactory 对象的 newMethodAccessor 方法生成一个,此处会返回一个代理了NativeMethodAccessorImpl 对象(delegate熟属性)的DelegatingMethodAccessorImpl对象。】,用ma.invoke()来返回反射的对象,此时便调用了NativeMethodAccessorImpl 的 invoke 方法,而在 NativeMethodAccessorImpl 的 invoke 方法里,其会判断调用次数是否超过阀值(numInvocations)。如果超过该阀值,那么就会生成另一个MethodAccessor 对象,并将原来 DelegatingMethodAccessorImpl 对象中的 delegate 属性指向最新的 MethodAccessor 对象。 实际的 MethodAccessor 实现有两个版本,一个是 Native 版本,一个是 Java 版本。

集合

String, Stringbuilder, Stringbuffer区别

  1. 可变与不可变。String类中使用字符数组保存字符串,因为有“final”修饰符,所以string对象是不可变的。对于已经存在的String对象的修改都是重新创建一个新的对象,然后把新的值保存进去.

String类利用了final修饰的char类型数组存储字符,源码如下:

private final char value[];

StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,这两种对象都是可变的。源码如下:

char[] value;
  1. 是否多线程安全。
    String中的对象是不可变的,也就可以理解为常量,显然线程安全。
    StringBuilder是非线程安全的。
    StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。
  2. 性能
    每次对String 类型进行改变的时候,都会生成一个新的String对象,然后将指针指向新的String 对象。StringBuffer每次都会对StringBuffer对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用StirngBuilder 相比使用StringBuffer 仅能获得10%~15% 左右的性能提升,但却要冒多线程不安全的风险。

HashMap原理(底层数据结构)

在JDK1.7 和JDK1.8 中有所差别:在JDK1.7 中,由“数组+链表”组成。数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的。

在JDK1.8 中,由“数组+链表+红黑树”组成。当链表过长,则会严重影响 HashMap 的性能,红黑树搜索时间复杂度是 O(logn),而链表是糟糕的 O(n)。因此,JDK1.8 对数据结构做了进一步的优化,引入了红黑树,链表和红黑树在达到一定条件会进行转换:

  • 当链表超过 8 且数据总量超过 64 才会转红黑树。
  • 将链表转换成红黑树前会判断,如果当前数组的长度小于 64,那么会选择先进行数组扩容,而不是转换为红黑树,以减少搜索时间。

HashMap存数据过程

  1. 首先根据 key 的值计算 hash 值,找到该元素在数组中存储的下标;
  2. 如果数组是空的,则调用 resize 进行初始化;
  3. 如果没有哈希冲突直接放在对应的数组下标里;
  4. 如果冲突了,且 key 已经存在,就覆盖掉 value;
  5. 如果冲突后,发现该节点是红黑树,就将这个节点挂在树上;
  6. 如果冲突后是链表,判断该链表是否大于 8 ,如果大于 8 并且数组容量小于 64,就进行扩容;如果链表节点大于 8 并且数组的容量大于 64,则将这个结构转换为红黑树;否则,链表插入键值对,若 key 存在,就覆盖掉 value。

CurrentHashMap原理

JDK1.7中的ConcurrentHashMap 是由 Segment 数组结构和 HashEntry 数组结构组成,即ConcurrentHashMap 把哈希桶切分成小数组(Segment ),每个小数组有 n 个 HashEntry 组成。
其中,Segment 继承了 ReentrantLock,所以 Segment 是一种可重入锁,扮演锁的角色;HashEntry 用于存储键值对数据。
首先将数据分为一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据时,其他段的数据也能被其他线程访问,能够实现真正的并发访问。

再来看下JDK1.8
在数据结构上, JDK1.8 中的ConcurrentHashMap 选择了与 HashMap 相同的数组+链表+红黑树结构;在锁的实现上,抛弃了原有的 Segment 分段锁,采用CAS + synchronized实现更加低粒度的锁。
将锁的级别控制在了更细粒度的哈希桶元素级别,也就是说只需要锁住这个链表头结点(红黑树的根节点),就不会影响其他的哈希桶元素的读写,大大提高了并发度。

CurrentHashMap存数据的过程

先来看JDK1.7
首先,会尝试获取锁,如果获取失败,利用自旋获取锁;如果自旋重试的次数超过 64 次,则改为阻塞获取锁。
获取到锁后:
将当前 Segment 中的 table 通过 key 的 hashcode 定位到 HashEntry。
遍历该 HashEntry,如果不为空则判断传入的 key 和当前遍历的 key 是否相等,相等则覆盖旧的 value。
不为空则需要新建一个 HashEntry 并加入到 Segment 中,同时会先判断是否需要扩容。
释放 Segment 的锁。

再来看JDK1.8
大致可以分为以下步骤:

  1. 根据 key 计算出 hash值。
  2. 判断是否需要进行初始化。
  3. 定位到 Node,拿到首节点 f,判断首节点 f:
    如果为 null ,则通过cas的方式尝试添加。
    如果为 f.hash = MOVED = -1 ,说明其他线程在扩容,参与一起扩容。
    如果都不满足 ,synchronized 锁住 f 节点,判断是链表还是红黑树,遍历插入。
  4. 当在链表长度达到8的时候,数组扩容或者将链表转换为红黑树。

多线程

线程的实现方式

  • 1.继承Thread类
  • 2.实现Runnable的接口
  • 3.使用Executorservice、callable、Future实现返回结果的多线程

runnable和callable的区别?

相同点:都是接口,都可以编写多线程程序,都采用Thread.Start()启动线程。
不同点:Runnable接口run方法无返回值,Callable接口Call方法有返回值,是个泛型,和Future、FutureTask配合来获取异步执行的结果。Runnable接口run方法只能抛出运行时的异常,并且无法捕获处理;Callable接口的call方法允许抛出异常,可以获取异常信息。Callable接口支持返回执行结果,需要调用FutureTask.get()得到,此方法会阻塞主进程的继续往下执行,如果不调用就不会阻塞。"

线程中wait()和sleep()方法有什么区别?

sleep()是Thread线程类的静态方法,wait()是object类的方法。
sleep()不释放锁;wait()释放锁。
wait通常被用于线程间交互/通信,sleep通常被用于暂停执行。
wait()方法被调用后,线程不会自动苏醒,需要别的线程调用同一个对象上的notify()或者notifyAll()方法。Sleep()方法执行完成后,线程会自动苏醒。或者可以调用wait(long timeOut)超时后线程或自动苏醒

线程池的几个参数介绍,常用队列以及线程池中拒绝策略?

  • corePoolSize 线程池核心线程大小
  • maximumPoolSize 线程池最大线程数量
  • keepAliveTime 空闲线程存活时间
  • unit 空闲线程存活时间单位
  • workQueue 工作队列
    • ArrayBlockingQueue:基于数组的有界阻塞队列,按FIFO排序,即先进先出原则。
    • LinkedBlockingQuene:基于链表的无界阻塞队列(其实最大容量为Interger.MAX),按照FIFO排序。
    • SynchronousQuene:一个不缓存任务的阻塞队列,生产者放入一个任务必须等到消费者取出这个任务。也就是说新任务进来时,不会缓存,而是直接被调度执行该任务,如果没有可用线程,则创建新线程,如果线程数量达到maxPoolSize,则执行拒绝策略
    • PriorityBlockingQueue:具有优先级的无界阻塞队列,优先级通过参数Comparator实现
  • threadFactory 线程工厂
  • handler 拒绝策略
    • CallerRunsPolicy:该策略下,在调用者线程中直接执行被拒绝任务的run方法,除非线程池已经shutdown,则直接抛弃任务
    • AbortPolicy:该策略下,直接丢弃任务,并抛出RejectedExecutionException异常。
    • DiscardPolicy:该策略下,直接丢弃任务,什么都不做。
    • DiscardOldestPolicy:该策略下,抛弃进入队列最早的那个任务,然后尝试把这次拒绝的任务放入队列

创建线程池的几种方式

  • newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
  • newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
  • newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
  • newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

synchronized的锁升级原理

在锁对象的对象头里面有一个threadid字段,在第一次访问的时候threadid为空,jvm让其持偏向锁,并将threadid设置为线程的id,再次进入的时候会先判断threadid是否与其它线程id一致,如果一致的话可以直接使用此对象,如果不一致,则升级偏向锁成为轻量级锁,通过自旋循环一定次数来获取锁,执行一定次数之后,如果还没有正常获取到要使用的对象,此时就会把锁从轻量级升级为重量级锁,这个过程就构成了 synchronized 锁的升级。

什么是死锁,如何避免死锁

死锁是指2个或2个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而照成的一种堵塞现象。 死锁就是2个线程要相互等待对方释放对象锁。

产生原因,如何避免死锁?

  • 1:互斥条件。 针对资源来说,资源在任意的时刻都应该由一个线程占用。
  • 2:请求保持条件。 一个进程因请求资源而阻塞时,对已经获得的资源保持不放(破坏:一次申请所有资源)
  • 3:不剥夺条件。 进程已获得的资源,在未使用完之前,不能进行强行剥夺。
  • 4:循环等待条件。很多进程之间形成一种首尾相接的循环等待。

只要其中的一个条件不成立的话, 就不会产生死锁。
互斥条件是无法破坏的。
比如:将系统中的所有资源标识设置标志位、排序,规定所有的线程申请资源必须按照一定的顺序来进行操作, 去避免循环等待。
破坏不剥夺条件: 占用部分资源的线程如果在去申请其他资源的时候,如果申请不到,可以主动师傅它只有的资源 。

Stream 流

Stream注意点?

  1. Stream自己不会存储元素。
  2. Stream不会改变源对象。相反,他们会返回一个持有结果的新Stream
  3. Stream操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
  4. 一旦调用了终结方法,流将不能再被使用,一旦调用非终结方法,原来旧的流不能再被使用了,只能用新的流进行操作。终结方法:如果返回值不为Stream流,如foreach,count方法;非终结方法:如果返回值为stream流,如filter,limit,skip,map,cancat等方法。

Stream并行流?并行流的原理

并行流就是把一个内容分成多个数据块,并用不同的线程分成多个数据块,并用不同的线程分别处理每个数据块的流。
采用了Fock/Join框架来进行对数据的并行处理,简单说就是将一个大任务进行拆分(Fock)成若干个小任务,再将一个个小任务运算的记过进行Join汇总。

创建Stream的方式

  1. 通过Collection系列集合提供的stream()方法或者paralleStream()方法来创建Stream
  2. 通过Arrays中的静态方法stream()获取数组流
  3. 通过Stream类的静态方法of()获取数组流
  4. 通过使用静态方法 Stream.iterate() 和Stream.generate(), 创建无限流

Stream的常用方法?

过滤:
filter:按条件过滤集合中的数据
distinct: distinct操作类似于我们在写SQL语句时,添加的DISTINCT关键字,用于去重处理,distinct基于Object.equals(Object)实现
limit:类似于SQL语句中的LIMIT关键字,不过相对功能较弱,limit返回包含前n个元素的流,当集合大小小于n时,则返回实际长度。
sorted:该操作用于对流中元素进行排序,sorted要求待比较的元素必须实现Comparable接口,如果没有实现也不要紧,我们可以将比较器作为参数传递给sorted(Comparator comparator)。
skip:skip操作与limit操作相反,如同其字面意思一样,是跳过前n个元素
映射:
map
flatMap
查找:
allMatch: 用于检测是否全部都满足指定的参数行为,如果全部满足则返回true
anyMatch: 则是检测是否存在一个或多个满足指定的参数行为,如果满足则返回true
noneMathch: 用于检测是否不存在满足指定行为的元素,如果不存在则返回true
findFirst: 用于返回满足条件的第一个元素
findAny: 相对于findFirst的区别在于,findAny不一定返回第一个,而是返回任意一个

stream 的分组操作:
1、Collectors.groupingBy来操作集合
Map groups = students.stream().collect(Collectors.groupingBy(Student::getSchool));
2、多级分组:
Map> groups2 = students.stream().collect(
Collectors.groupingBy(Student::getSchool, // 一级分组,按学校
Collectors.groupingBy(Student::getMajor))); // 二级分组,按专业
3、Collector.counting,分组后统计个数:

SpringBoot

springboot启动流程

SpringBoot应用程序的启动流程主要包括初始化SpringApplication和运行SpringApplication两个过程。1.初始化SpringApplication:配置基本的环境变量、资源、构造器和监听器,为运行SpringApplciation实例对象作准备;2.SpringApplication.run():SpringApplicationRunListeners 引用启动监控模块、ConfigrableEnvironment配置环境模块和监听及ConfigrableApplicationContext配置应用上下文。当完成刷新应用的上下文和调用SpringApplicationRunListener#contextPrepared方法后表示SpringBoot应用程序已经启动完成。

Redis

redis高可用的方案?

  1. 主从复制
  2. 哨兵模式
  3. 集群

主从复制原理以及优缺点

主从复制原理:
主节点(master)负责读写,从节点(slave)负责读。这个系统的运行依靠三个主要的机制:
a. 当一个 master 实例和一个 slave 实例连接正常时, master 会发送一连串的命令流来保持对 slave 的更新,以便于将自身数据集的改变复制给 slave ,包括客户端的写入、key 的过期或被逐出等等。
b. 当 master 和 slave 之间的连接断开之后,因为网络问题、或者是主从意识到连接超时, slave 重新连接上 master 并会尝试进行部分重同步:这意味着它会尝试只获取在断开连接期间内丢失的命令流。
c. 当无法进行部分重同步时, slave 会请求进行全量重同步。这会涉及到一个更复杂的过程,例如 master 需要创建所有数据的快照,将之发送给 slave ,之后在数据集更改时持续发送命令流到 slave 。

主从复制优缺点:
优点:
a. 高可靠性,采用双机主备架构,能够在主库出现故障时自动进行主备切换,从库提升为主库提供服务,保证服务平稳运行。另一方面,开启数据持久化功能和配置合理的备份策略,能有效的解决数据误操作和数据异常丢失的问题
b. 读写分离策略,从节点可以扩展主库节点的读能力,能有效应对大并发量的读操作。
弊端:
a. 故障恢复复杂,主节点挂了之后,需要手动将一个从节点晋升为主节点,同事需要通知业务方变更配置,并且需要让其他从节点去复制新的主节点,整个过程需要人为干预,比较繁琐。
b. 主库的写能力受到单机的限制,可以考虑分片
c. 主库的存储能力受到单机的限制,可以考虑Pika
d. 丛节点复制数据有弊端。

哨兵模式原理以及优缺点

哨兵模式:
原理:Redis Sentinel是社区版本推出的原生高可用解决方案,其部署架构主要包括两部分:Redis Sentinel集群和Redis数据集群。
其中Redis Sentinel集群是由若干Sentinel节点组成的分布式集群,可以实现故障发现、故障自动转移、配置中心和客户端通知。
Redis Sentinel的节点数量要满足2n+1(n>=1)的奇数个

哨兵模式优缺点:
优点:
a. redis sentinel 集群部署简单
b. 能够解决主从模式下的高可用切换问题
c. 很方便实现Redis数据节点的线性扩展,轻松突破Redis自身单线程瓶颈,可极大满足Redis大容量或高性能的业务需求
d. 可以实现一套Sentinel监控一组Redis数据节点或多组数据节点

缺点:
a. 资源浪费,Redis数据节点中slave节点作为备份节点不提供服务;
b. Redis Sentinel主要是针对Redis数据节点中的主节点的高可用切换,对Redis的数据节点做失败判定分为主观下线和客观下线两种,对于Redis的从节点有对节点做主观下线操作,并不执行故障转移。
c. 不能解决读写分离问题,实现起来相对复杂。

集群模式原理、分片算法、优缺点?

集群的原理:
Redis Cluster是社区版推出的Redis分布式集群解决方案,主要解决Redis分布式方面的需求,比如,当遇到单机内存,并发和流量等瓶颈的时候,Redis Cluster能起到很好的负载均衡的目的。
Redis Cluster集群节点最小配置6个节点以上(3主3从),其中主节点提供读写操作,从节点作为备用节点,不提供请求,只作为故障转移使用。
Redis Cluster采用虚拟槽分区,所有的键根据哈希函数映射到0~16383个整数槽内,每个节点负责维护一部分槽以及槽所印映射的键值数据。

集群模式下多个master节点,是怎么解决数据分片问题的? 希望数据平均分配的话,用的什么算法?
1、 哈希取模算法:
当有n个节点得时候,此时这多个节点都是正常得,这些节点都是固定有序得。
当存储一个数据,会对这个数据得key获取哈希值然后进行取模操作,取模得到得值肯定不会大于节点数量得。
通过得到的值去操作对应的节点。
如果此时,有一个节点挂机了,等于之前节点的顺序改变了。除了失去了这个节点上面得数据外,
若此时对key进行哈希取模,就会发现得到的值很有可能找不到对应的节点去拿了,
这就可能丢掉得不只是一个节点得数据。
2、 一致性哈希算法
一致性哈希的原理: 把所有的哈希值空间组织成一个虚拟的圆环(哈希环),整个空间按顺时针方向组织。
因为是环形空间,0 和 2^32-1 是重叠的。 假设我们有四台机器要哈希环来实现映射(分布数据),
我们先根据机器的名称或者 IP 计算哈希值,然后分布到哈希环中(红色圆圈)。

集群的优缺点
优点:
a. 无中心架构;
b. 数据按照slot存储分布在多个节点,节点间数据共享,可动态调整数据分布;
c. 可扩展性:可线性扩展到1000多个节点,节点可动态添加或删除;
d. 高可用性:部分节点不可用时,集群仍可用。通过增加Slave做standby数据副本,能够实现故障自动failover,节点之间通过gossip协议交换状态信息,用投票机制完成Slave到Master的角色提升;
e. 降低运维成本,提高系统的扩展性和可用性

缺点:
a. 数据通过异步复制,不保证数据的强一致性。
b. 节点会因为某些原因发生阻塞(阻塞时间大于clutser-node-timeout),被判断下线,这种failover是没有必要的。
c. 多个业务使用同一套集群时,无法根据统计区分冷热数据,资源隔离性较差,容易出现相互影响的情况。
d. 不支持多数据库空间,单机下的redis可以支持到16个数据库,集群模式下只能使用1个数据库空间,即db0。

缓存穿透、缓存雪崩?如何避免此类问题

缓存穿透,缓存雪崩问题,如何避免?
缓存穿透说简单点就是大量请求的 key 根本不存在于缓存中,导致请求直接到了数据库上,根本没有经过缓存这一层
缓存雪崩就是缓存在同一时间大面积的失效,后面的请求都直接落到了数据库上,造成数据库短时间内承受大量请求

缓存穿透解决方案:

  1. 最基本的就是首先做好参数校验,一些不合法的参数请求直接抛出异常信息返回给客户端。
  2. 缓存无效额的key: 缓存和数据库都查不到某个 key 的数据就写一个到 Redis 中去并设置过期时间。这种方式可以解决请求的 key 变化不频繁的情况,如果黑客恶意攻击,每次构建不同的请求 key,会导致 Redis 中缓存大量无效的 key
  3. 布隆过滤器: 把所有可能存在的请求的值都存放在布隆过滤器中,当用户请求过来,先判断用户发来的请求的值是否存在于布隆过滤器中。不存在的话,直接返回请求参数错误信息给客户端,存在的话才会走下面的流程。

缓存雪崩解决方案:

  1. 采用 Redis 集群,避免单机出现问题整个缓存服务都没办法使用。
  2. 限流,避免同时处理大量的请求。
  3. 设置不同的失效时间比如随机设置缓存的失效时间。
  4. 对于一些热点,不宜改动的数据直接设置缓存永不失效。

缓存的淘汰策略以及Redis中的淘汰策略

缓存淘汰策略
LRU(Least Recently Used):淘汰最近最少使用的key。在缓存写满的时候,会根据所有数据的访问记录,淘汰掉未来被访问几率最低的数据
LFU(Least Frequently Used):优先淘汰最不常用的、使用最少的key,LFU的侧重点是缓存的使用频率,系统有大量热点缓存数据可能更适合
FIFO(First In First Out): 先进先出。即先缓存进来的数据会优先被淘汰。
RANDOM: 随机。随机淘汰,适用于缓存数据被访问的概率差不多时

Redis的淘汰策略:
allkeys-lru:从所有 key 中使用 LRU 算法,选出最近使用最少的数据进行淘汰;
volatile-lru:从设置了过期时间的 key 中使用 LRU 算法,选出最近使用最少的数据进行淘汰;
allkeys-lfu:从所有 key 中使用 LFU 算法,选出使用频率最低的数据,进行淘汰;
volatile-lfu:从设置了过期时间的 key 中使用 LFU 算法,选出使用频率最低的数据进行淘汰;
allkeys-random:从所有的 key 中,随机选出数据进行淘汰;
volatile-random:从设置了过期时间的 key 中,随机选出数据进行淘汰;
volatile-ttl:从设置了过期时间的 key 中,选出即将过期的数据(按照过期时间的先后,选出最先过期的数据)进行淘汰;
noeviction:禁止淘汰数据,写入操作报错。这是 Redis 默认的内存淘汰策略。

MySQL数据库

索引失效原因

  • 隐式的类型转换,索引失效
  • 查询条件包含or,可能导致索引失效
  • like通配符可能导致索引失效
  • 查询条件不满足联合索引的最左匹配原则
  • 在索引列上使用mysql的内置函数
  • 对索引进行列运算(如,+、-、*、/),索引不生效
  • 索引字段上使用(!= 或者 < >),索引可能失效
  • 索引字段上使用is null, is not null,索引可能失效
  • 左右连接,关联的字段编码格式不一样
  • 优化器选错了索引

相关内容

热门资讯

长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...