问题来历如下:

蔚来真题和答案,主打一个简单?

问题链接:www.nowcoder.com/discuss/493…

答案解析

1.解说脏读/不可重复读/幻读

  • 脏读:指一个事务读取到了另一个事务为提交保存的数据,之后此事务进行了回滚操作,然后导致第一个事务读取了一个不存在的脏数据。
  • 不可重复读:在同一个事务中,同一个查询在不同的时刻得到了不同的成果。例如事务在 T1 读取到了某一行数据,在 T2 时刻从头读取这一行时候,这一行的数据已经产生修正,所以再次读取时得到了一个和 T1 查询时不同的成果。
  • 幻读:同一个查询在不同时刻得到了不同的成果,这便是事务中的幻读问题。例如,一个 SELECT 被履行了两次,但是第2次回来了第一次没有回来的一行,那么这一行便是一个“幻像”行。

不可重复读和幻读的差异

  • 不可重复读的重点是修正:在同一事务中,相同的条件,第一次读的数据和第2次读的数据不一样。(由于中心有其他事务提交了修正);
  • 幻读的重点在于新增或者删去:在同一事务中,相同的条件,,第一次和第2次读出来的记载数不一样。(由于中心有其他事务提交了刺进/删去)。

2.索引失效的场景有哪些?

常见的索引失效场景有以下这些:

  1. 未遵循最左匹配准则
  2. 运用列运算
  3. 运用函数方法
  4. 类型转换
  5. 运用 is not null
  6. 过错的含糊匹配,运用右 % 开始查询。

具体内容请参阅:www.javacn.site/interview/m…

3.Explain履行计划用过吗?

Explain 是用来分析 SQL 的履行情况的,explain 运用如下,只需求在查询的 SQL 前面添加上 explain 关键字即可,如下图所示:

蔚来真题和答案,主打一个简单?
而以上查询成果的列中,咱们最首要观察 key 这一列,key 这一列表明实际运用的索引,假如为 NULL 则表明未运用索引,反之则运用了索引。

以上一切成果列阐明如下:

  • id — 挑选标识符,id 越大优先级越高,越先被履行;
  • select_type — 表明查询的类型;
  • table — 输出成果集的表;
  • partitions — 匹配的分区;
  • type — 表明表的查询类型;
  • possible_keys — 表明查询时,或许运用的索引;
  • key — 表明实际运用的索引;
  • key_len — 索引字段的长度;
  • ref— 列与索引的比较;
  • rows — 大概估算的行数;
  • filtered — 按表条件过滤的行百分比;
  • Extra — 履行情况的描述和阐明。

4.Type字段有什么信息?

Explain 履行计划中最重要的便是 type 字段,type 包括的信息如下:

  • all — 扫描全表数据;
  • index — 遍历索引;
  • range — 索引范围查找;
  • index_subquery — 在子查询中运用 ref;
  • unique_subquery — 在子查询中运用 eq_ref;
  • ref_or_null — 对 null 进行索引的优化的 ref;
  • fulltext — 运用全文索引;
  • ref — 运用非仅有索引查找数据;
  • eq_ref — 在 join 查询中运用主键或仅有索引关联;
  • const — 将一个主键放置到 where 后面作为条件查询, MySQL 优化器就能把这次查询优化转化为一个常量,如何转化以及何时转化,这个取决于优化器,这个比 eq_ref 功率高一点。

5.binlog和redolog差异?

binlog(二进制日志)和 redolog(重做日志)都是 MySQL 中的重要日志,但二者存在以下不同。

  1. binlog(二进制日志):
    • binlog 是 MySQL 的服务器层日志,用于记载对数据库履行的一切修正操作,包括刺进、更新和删去等。它以二进制格局记载,能够被用于数据仿制、康复和毛病康复等操作。
    • binlog 记载了逻辑上的操作,即履行的 SQL 句子或句子的逻辑表明。
    • binlog 是在事务提交后才会生成,因此它是耐久化的。
    • binlog 能够被配置为不同的格局,包括基于句子的仿制(statement-based replication)、基于行的仿制(row-based replication)和混合仿制(mixed replication)。
  2. redolog(重做日志):
    • redolog 是 MySQL 的存储引擎层日志,用于确保数据库的事务耐久性和溃散康复能力。
    • redolog 记载了物理层面的修正操作,即对数据页的物理修正。它首要用于确保事务的耐久性,确保在产生溃散时,已经提交的事务对数据库的修正能够被康复。
    • redolog 是循环写入的,它的数据写入到磁盘上的文件中。在产生溃散时,经过 redolog 的重做操作,能够将数据库康复到溃散前的一致状态。
    • redolog 是在事务履行期间不断写入的,以确保在体系溃散时能够重做一切已提交的事务。

小结:binlog 用于记载逻辑层面的操作,能够用于数据仿制和康复,而 redolog 用于记载物理层面的操作,确保事务的耐久性和溃散康复。它们在功用和运用上有一些不同,但都是 MySQL 中重要的日志机制。

6.Redis根本数据类型

Redis 常用的数据类型有 5 种:String 字符串类型、List 列表类型、Hash 哈希表类型、Set 调集类型、Sorted Set 有序调集类型,如下图所示: 这 5 种常用类型的用处如下:

  1. String:字符串类型,常见运用场景是:存储 Session 信息、存储缓存信息(如详情页的缓存)、存储整数信息,可运用 incr 完成整数+1,和运用 decr 完成整数 -1;
  2. List:列表类型,常见运用场景是:完成简略的消息行列、存储某项列表数据;
  3. Hash:哈希表类型,常见运用场景是:存储 Session 信息、存储产品的购物车,购物车非常适合用哈希字典表明,运用人员仅有编号作为字典的 key,value 值能够存储产品的 id 和数量等信息、存储详情页信息;
  4. Set:调集类型,是一个无序并仅有的键值调集,它的常见运用场景是:重视功用,比方重视我的人和我重视的人,运用调集存储,能够确保人员不会重复;
  5. Sorted Set:有序调集类型,相比于 Set 调集类型多了一个排序特点 score(分值),它的常见运用场景是:能够用来存储排名信息、重视列表功用,这样就能够依据重视完成排序展示了。

更多内容请参阅:www.javacn.site/interview/r…

7.有序调集底层完成数据结构?

有序调集是由 ziplist (紧缩列表) 或 skiplist (跳动表) 组成的。

  1. 紧缩列表 ziplist 本质上便是一个字节数组,是 Redis 为了节约内存而规划的一种线性数据结构,能够包括多个元素,每个元素能够是一个字节数组或一个整数。
  2. 跳动表 skiplist 是一种有序数据结构,它经过在每个节点中保持多个指向其他节点的指针,然后达到快速拜访节点的意图。跳动表支持均匀 O(logN)、最坏 O(N) 复杂度的节点查找,还能够经过次序性操作来批量处理节点。

当数据比较少时,有序调集是紧缩列表ziplist存储的(反之则为跳动表 skiplist 存储),运用紧缩列表存储必满意以下两个条件:

  1. 有序调集保存的元素个数要小于 128 个;
  2. 有序调集保存的一切元素成员的长度都必须小于 64 字节。

假如不能满意以上两个条件中的恣意一个,有序调集将会运用跳动表 skiplist 结构进行存储。

8.跳表刺进数据的进程?

在开始讲跳动表的添加流程之前,必须先搞懂一个概念:节点的随机层数。 所谓的随机层数指的是每次添加节点之前,会先生成当前节点的随机层数,依据生成的随机层数来决定将当前节点存在几层链表中。

为什么要这样规划呢?

这样规划的意图是为了确保 Redis 的履行功率。

为什么要生成随机层数,而不是拟定一个固定的规矩,比方上层节点是基层跨过两个节点的链表组成,如下图所示:

蔚来真题和答案,主打一个简单?

假如拟定了规矩,那么就需求在添加或删去时,为了满意其规矩,做额外的处理,比方添加了一个新节点,如下图所示:

蔚来真题和答案,主打一个简单?
这样就不满意拟定的上层节点跨过基层两个节点的规矩了,就需求额外的调整上层中的一切节点,这样程序的功率就降低了,所以运用随机层数,不强制拟定规矩,这样就不需求进行额外的操作,然后也就不会占用服务履行的时刻了。

添加流程

Redis 中跳动表的添加流程如下图所示:

蔚来真题和答案,主打一个简单?

  1. 第一个元素添加到最底层的有序链表中(最底层存储了一切元素数据)。
  2. 第二个元素生成的随机层数是 2,所以再添加 1 层,并将此元素存储在第 1 层和最低层。
  3. 第三个元素生成的随机层数是 4,所以再添加 2 层,整个跳动表变成了 4 层,将此元素保存到一切层中。
  4. 第四个元素生成的随机层数是 1,所以把它按次序保存到最后一层中即可。

其他新增节点以此类推。 更多内容请参阅:www.javacn.site/company/red…

9.线程池有哪些参数?

线程池(ThreadPoolExecutor)有 7 个参数,这 7 个参数的意义如下:

  • 第 1 个参数:corePoolSize 表明线程池的常驻中心线程数。假如设置为 0,则表明在没有任何使命时,毁掉线程池;假如大于 0,即使没有使命时也会确保线程池的线程数量等于此值。但需求留意,此值假如设置的比较小,则会频频的创立和毁掉线程(创立和毁掉的原因会在本课时的下半部分讲到);假如设置的比较大,则会浪费体系资源,所以开发者需求依据自己的实际事务来调整此值;
  • 第 2 个参数:maximumPoolSize 表明线程池在使命最多时,最大能够创立的线程数。官方规定此值必须大于 0,也必须大于等于 corePoolSize,此值只有在使命比较多,且不能存放在使命行列时,才会用到;
  • 第 3 个参数:keepAliveTime 表明线程的存活时刻,当线程池空闲时而且超过了此时刻,剩余的线程就会毁掉,直到线程池中的线程数量毁掉的等于 corePoolSize 为止,假如 maximumPoolSize 等于 corePoolSize,那么线程池在空闲的时候也不会毁掉任何线程;
  • 第 4 个参数:unit 表明存活时刻的单位,它是合作 keepAliveTime 参数共同运用的;
  • 第 5 个参数:workQueue 表明线程池履行的使命行列,当线程池的一切线程都在处理使命时,假如来了新使命就会缓存到此使命行列中排队等候履行;
  • 第 6 个参数:threadFactory 表明线程的创立工厂,此参数一般用的比较少,咱们通常在创立线程池时不指定此参数,它会运用默许的线程创立工厂的方法来创立线程;
  • 第 7 个参数:RejectedExecutionHandler 表明指定线程池的回绝战略,当线程池的使命已经在缓存行列 workQueue 中存储满了之后,而且不能创立新的线程来履行此使命时,就会用到此回绝战略,它归于一种限流保护的机制。

更多内容请参阅:/post/707292…

10.回绝战略有哪些?

线程池的回绝战略默许有以下 4 种:

  1. AbortPolicy:间断战略,线程池会抛出异常并间断履行此使命;
  2. CallerRunsPolicy:把使命交给添加此使命的(main)线程来履行;
  3. DiscardPolicy:疏忽此使命,疏忽最新的一个使命;
  4. DiscardOldestPolicy:疏忽最早的使命,最早加入行列的使命。

默许的回绝战略为 AbortPolicy 间断战略。当然除了 JDK 内置的 4 种回绝战略之外,用户还能够自界说回绝战略,经过完成 new RejectedExecutionHandler,并重写 rejectedExecution 方法来完成自界说回绝战略,完成代码如下:

public static void main(String[] args) {
    // 使命的具体方法
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            System.out.println("当前使命被履行,履行时刻:" + new Date() +
                               " 履行线程:" + Thread.currentThread().getName());
            try {
                // 等候 1s
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    };
    // 创立线程,线程的使命行列的长度为 1
    ThreadPoolExecutor threadPool = new ThreadPoolExecutor(1, 1,
                                                           100, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1),
                                                           new RejectedExecutionHandler() {
                                                               @Override
                                                               public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                                                                   // 履行自界说回绝战略的相关操作
                                                                   System.out.println("我是自界说回绝战略~");
                                                               }
                                                           });
    // 添加并履行 4 个使命
    threadPool.execute(runnable);
    threadPool.execute(runnable);
    threadPool.execute(runnable);
    threadPool.execute(runnable);
}

11.你常用的回绝战略是哪种?为什么?

最常用的回绝战略是自界说回绝战略,由于里边能够完成自己的事务代码,比方,咱们能够经过自界说回绝战略,发送警告信息给相关人员,这样就能及时发现程序履行的问题,同时再将回绝的使命记载下来,让开发人员手动处理,这样就能够及时发现问题,并解决问题了。

12.三个线程替换打印ABC

三个线程替换打印 ABC 的完成方法有很多,我个人比较倾向于运用 JUC 下的 CyclicBarrier(循环栅门,也叫循环屏障)来完成,由于循环栅门天生便是用来完成一轮一轮多线程使命的,它的完成代码如下:

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
 * 3 个线程替换打印 ABC
 */
public class ThreadLoopPrint {
    // 同享计数器
    private static int sharedCounter = 0;
    public static void main(String[] args) {
        // 打印的内容
        String printString = "ABC";
        // 界说循环栅门
        CyclicBarrier cyclicBarrier = new CyclicBarrier(3, () -> {
        });
        // 履行使命
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < printString.length(); i++) {
                    synchronized (this) {
                        sharedCounter = sharedCounter > 2 ? 0 : sharedCounter; // 循环打印
                        System.out.println(printString.toCharArray()[sharedCounter++]);
                    }
                    try {
                        // 等候 3 个线程都打印一遍之后,持续走下一轮的打印
                        cyclicBarrier.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        // 敞开多个线程
        new Thread(runnable).start();
        new Thread(runnable).start();
        new Thread(runnable).start();
    }
}

以上程序履行的成果如下图所示:

蔚来真题和答案,主打一个简单?
更多内容请参阅:www.javacn.site/interview/c…

13.力扣括号生成

参阅官方解题思路和完成代码:leetcode.cn/problems/ge…

参阅&道谢

我没有三颗心脏

本文已收录到我的面试小站 www.javacn.site,其中包括的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、规划模式、消息行列等模块。