其他相关问题
如何查看 MySQL 服务被多少个客户端连接了?
mysql> show processlist;
空闲连接会一直占用着吗?
- 空闲连接的最大空闲时长,由 wait_timeout 参数控制的
- 查询命令
mysql> show variables like 'wait_timeout';
- 手动断开
mysql> kill connection +6;
MySQL 的连接数有限制吗?
MySQL 服务支持的最大连接数由 max_connections 参数控制。
MySQL 的连接也跟 HTTP 一样,有短连接和长连接的概念。
怎么解决长连接占用内存的问题?
- 定期断开长连接
- 客户端主动重置连接
第二步:查询缓存
过程
解析出 SQL 语句的第一个字段,看看是什么类型的语句。
如果 SQL 是查询语句(select 语句),MySQL 就会先去查询缓存( Query Cache )里查找缓存数据。
如果查询的语句命中查询缓存,那么就会直接返回 value 给客户端。
如果查询的语句没有命中查询缓存中,那么就要往下继续执行,等执行完后,查询的结果就会被存入查询缓存中。
缺点
- 更新比较频繁的表,查询缓存的命中率很低
版本变动
- MySQL 8.0 版本直接将查询缓存删掉了,也就是说 MySQL 8.0 开始,执行一条 SQL 查询语句,不会再走到查询缓存这个阶段了。对于 MySQL 8.0 之前的版本,如果想关闭查询缓存,我们可以通过将参数 query_cache_type 设置成 DEMAND。
这里说的查询缓存是 server 层的,也就是 MySQL 8.0 版本移除的是 server 层的查询缓存,并不是 Innodb 存储引擎中的 buffer pool。
第三步:解析 SQL
过程
- 词法分析
- 语法分析
- 语法不对,解析器就会给报错
注意:表不存在或者字段不存在,并不是在解析器里做的,解析器只负责构建语法树和检查语法,但是不会去查表或者字段存不存在。
第四步:执行 SQL
过程
- prepare 阶段,也就是预处理阶段;
- optimize 阶段,也就是优化阶段;
- execute 阶段,也就是执行阶段;
1 预处理器
检查 SQL 查询语句中的表或者字段是否存在;
将 select * 中的 * 符号,扩展为表上的所有列;
2 优化器
优化器主要负责将 SQL 查询语句的执行方案确定下来
比如在表里面有多个索引的时候,优化器会基于查询成本的考虑,来决定选择使用哪个索引。
要想知道优化器选择了哪个索引,我们可以在查询语句最前面加个 explain 命令
3 执行器
执行器就会和存储引擎交互了,交互是以记录为单位的。
三种方式执行过程
- 主键索引查询
- 全表扫描
- 索引下推(MySQL 5.6 推出的查询优化策略)
特点
- 执行器查询的过程是一个 while 循环
- Server 层每从存储引擎读到一条记录就会发送给客户端,之所以客户端显示的时候是直接显示所有记录的,是因为客户端是等查询语句查询完成后,才会显示出所有的记录
总结
执行一条 SQL 查询语句,期间发生了什么?
-
连接器:建立连接,管理连接、校验用户身份;
-
查询缓存:查询语句如果命中查询缓存则直接返回,否则继续往下执行。MySQL 8.0 已删除该模块;
-
解析 SQL,通过解析器对 SQL 查询语句进行词法分析、语法分析,然后构建语法树,方便后续模块读取表名、字段、语句类型;
-
执行 SQL:执行 SQL 共有三个阶段:
- 预处理阶段:检查表或字段是否存在;将 select * 中的 * 符号扩展为表上的所有列。
- 优化阶段:基于查询成本的考虑,选择查询成本最小的执行计划;
- 执行阶段:根据执行计划执行 SQL 查询语句,从存储引擎读取记录,返回给客户端;
连接器:客户端首先进行身份验证,如果没通过直接返回。
查询缓存:如果身份验证不通过则查询缓存。缓存这个原理很容易理解,就是把常用的数据放到更高效的地方便于查询。查询缓存也有缺点,就是每当数据更改的时候就要重新设置缓存,在 MySQL8.0 已经将查询缓存去掉。
分析器:分析器先会做“词法分析”。把你输入的内容进行识别,知道字符分别代表什么,有什么含义 然后进行语法分析,如果你的 SQL 语句不符合 MySQL 语法就会收到错误提醒。
优化器:优化器作用就是决定使用哪个索引,决定 join 表的连接顺序。优化器会选择它自己认为最高效的方案,(也代表它不一定能选择出最优的方案)。
执行器:执行器还是先会判断有没有执行的权限,如果有权限的话才会执行下一步。遍历满足条件的行,并把组成的记录集作为结果集返回给客户端。
题目二
什么是 IOC,简单讲一下 Spring IOC 的实现机制?
IOC (Inversion of Control),中文翻译为控制反转,是一种编程思想,它将程序中对象的创建、组装、管理等控制权从代码中转移到框架中,实现了松耦合和可重用性的设计。
Spring IOC 是 Spring 框架的一个核心特性,它的实现机制主要包括以下几个步骤:
- 定义 Bean:在 Spring IOC 中,所有的对象都被看作是 Bean,需要在配置文件或者使用注解的方式中进行定义和配置。
- 创建 Bean 工厂:在 Spring 中,Bean 工厂负责管理 Bean 的创建、组装和销毁等任务。Spring IOC 容器就是 Bean 工厂的一种实现。
- 读取配置文件:Spring IOC 容器会读取配置文件或者使用注解的方式来获取 Bean 的定义和配置信息。
- 创建 Bean 实例:Spring IOC 容器根据配置文件中的信息,使用反射技术来创建 Bean 实例,并将其保存在容器中。
- 组装 Bean:Spring IOC 容器根据配置文件中的信息,将不同的 Bean 实例组装起来,形成一个完整的应用程序。
- 注入依赖:Spring IOC 容器根据配置文件中的信息,自动为 Bean 注入依赖的对象或者值。
- 提供 Bean 实例:应用程序通过 Spring IOC 容器获取需要的 Bean 实例,从而使用其中的方法和属性等。
需要注意的是,Spring IOC 还提供了多种作用域,例如单例、原型、会话、请求等作用域,可以根据具体的需求来选择。
同时,Spring IOC 容器也支持 AOP、事务管理等功能,可以为应用程序提供更完整的服务。
什么是IOC容器,以及IOC的创建过程
基本概念
- IOC(Inverse Of Controll,控制反转):就是原来代码里面需要自己手动创建的对象,依赖,反转给 Spring 来帮忙实现。我们需要创建一个容器,同时需要一种描述来让容器知道要创建的对象与对象之间的关系。
- 在 Spring 中 BeanFactory 就是 IOC 容器,在 Spring 初始化的时候,创建容器,并将需要创建对象和对象的关系(xml,注解)通过 BeanDefinitionReader 加载到 BeanDefinition 中并保存在 BeanDefinitionMap 中,然后再由 IOC 容器创建 bean 对象.
两种 bean 的注册方式
- 方法1:通过 @Bean + @Configuration 的方式直接定义要创建的对象与对象的关系
- 方式2:通过 @Component 定义类,这种方式必须使用 @ComponetScan 定位 Bean 扫描路径
IOC的创建
- 在 Spring 中 BeanFactory 就是 IOC 容器,在 Spring 初始化的时候,创建容器,并将需要创建对象和对象的关系(xml,注解)通过 BeanDefinitionReader 加载到 BeanDefinition 中并保存在 BeanDefinitionMap 中,在这个过程中会让 BeanDefinitionProcesser(Bean 的定义信息的后置处理器)进行增强,然后再由 IOC 容器创建 bean 对象.
Bean的生命周期(面试官顺着问题往下问的拓展)
-
bean 的实例化:spring 启动后,会查找和加载需要被 spring 管理的 Bean,并且实例化
-
bean 的属性注入(bean 的初始化):bean 被实例化后将 Bean 的引用和值注入到 bean 的属性中
- 查看是否调用一些 aware 接口,比如 BeanFactoryAware,BeanFactoryAware,ApplicationContextAware 接口,分别会将 Bean 的名字,BeanFactory 容器实例,以及 Bean 所在的上下文引用传入给 Bean
- 在初始化之前,会查看是否调用了 BeanPostProcessor 的预初始化方法,可以对 bean 进行扩展
- 调用 InitializingBean 的 afterPropertiesSet()方法:如果 Bean 实现了 InitializingBean 接口,spring 将调用他们的afterPropertiesSet()方法,类似的,如果 Bean 使用 init-method 生命了初始化方法的话,这个方法也会被调用。
- 初始化成功之后,会查看是否调用 BeanPostProcessor 的初始化后的方法:如果 Bean 实现了 BeanPostProcessor 接口,spring 就将调用他们的 postprocessAfterInitialization()方法。可以对 bean 进行扩展
-
bean的正常使用:可以被应用程序正常使用了,他们将驻留在上下文中,直到应用的上下文被销毁
-
bean的销毁:调用 DisposableBean 的destory()方法:如果 Bean 实现 DisposableBean 接口,spring 将用他的 destory()方法,相同的,如果 Bean 使用了 destory-method 生命销毁方法,该方法也会被调用。(但由于 bean 也分为单例和多例,单例 bean 会随着 IOC 容器的销毁而销毁,多例的 bean 不会随着 IOC 容器的销毁而销毁,他是通过 JVM 里面的垃圾回收器负责回收)
题目三
并发和并行有什么区别?同步和异步有什么区别?
并发和并行是两个计算机领域中经常被提到的概念,它们的含义有所不同。
- 并发(Concurrency):指的是系统中同时存在多个正在执行的任务,并且这些任务之间可能会相互影响。并发通常用来处理多个任务共享资源的情况。在单核 CPU 上,多个任务会轮流使用 CPU 时间片,表现为看似同时执行的情况,但实际上只有一个任务正在执行。
- 并行(Parallelism):指的是系统中同时存在多个并且相互独立的任务,并且这些任务可以在多个处理器上同时执行,真正意义上的同时处理多个任务。
- 同步(Synchronous):指的是程序按照代码的顺序执行,一行一行地执行,直到当前行执行完成后才能继续执行下一行。同步通常会阻塞调用者,直到任务完成才能返回。
- 异步(Asynchronous):指的是程序在执行某个任务时,不会一直等待任务完成,而是继续执行下一行代码,当任务完成后再进行相应的处理。异步通常不会阻塞调用者,可以提高系统的并发性能。
总的来说,"并发"和"并行"是针对多个任务的执行方式,"同步"和"异步"是针对任务执行的阻塞方式和返回方式。在实际应用中,可以根据不同的需求来选择合适的并发和同步方式,以提高系统的性能和可靠性。
先介绍并发和并行的区别:
并发:指多个任务同时在执行,但是它们并不是在同一时刻执行,而是通过快速切换上下文来模拟同时执行,优秀的并发可以无限逼近并行,但无法完全做到并行。
例如,在一个 Web 服务器上,多个用户访问同一个网站,服务器会并发地处理这些请求,同时响应每个请求,但是在某一时刻只有一个请求被处理;
并行:指多个任务同时在执行,并且它们真正地同时执行,通常需要多个 CPU 或者多台计算机协同工作。
例如,在一个分布式计算系统中,不同的计算节点可以同时执行不同的任务,并在完成任务后将结果汇总,以加速计算的过程。
接下来是同步和异步:
同步:指调用某个函数或方法时,程序必须等待函数或方法执行完毕才能继续往下执行。
最熟知的便是使用同步机制来控制多个线程之间的访问,如在 Java 中的 synchronized 关键字可以确保同一时间只有一个线程可以访问某个对象的临界区,避免了多个线程同时修改同一个对象导致的数据不一致问题;
异步:指调用某个函数或方法时,程序可以继续往下执行,不必等待函数或方法执行完毕。当函数或方法执行完毕后,程序会得到一个通知或回调来处理结果。在 Java 中可以使用 CompletableFuture 类来异步执行某个任务,从而提高程序的性能。
虽然并发和并行、同步和异步都是计算机领域中常用的概念,但是它们的区别还是很明显的。并发和并行关注的是任务的执行方式,同步和异步则关注的是数据的处理方式。
前端
题目一
用 CSS 和 JS 来实现动画分别有哪些优缺点?
用 CSS 和 JS 来实现动画各有其优缺点,具体如下:
使用 CSS 实现动画的优缺点:
优点:
- 硬件加速:CSS 动画会使用浏览器的 GPU 来进行硬件加速,能够更加流畅和高效地运行。
- 简单易用:CSS 动画通常只需要几行代码就能实现基本的动画效果,不需要使用 JavaScript 来控制动画。
- 低资源占用:CSS 动画通常比 JavaScript 动画使用更少的 CPU 和内存资源,因此更适合用于简单的动画效果。
缺点:
- 限制较大:CSS 动画在实现复杂的动画效果时,受到限制较大,不能像 JavaScript 动画那样自由控制动画的速度、方向等。
- 兼容性问题:由于不同浏览器对 CSS 动画支持程度不同,因此在实现时需要考虑浏览器兼容性问题。
- 可维护性差:当动画效果较为复杂时,使用 CSS 实现的代码会变得冗长和难以维护,因此需要进行代码优化和结构设计。
使用 JavaScript 实现动画的优缺点:
优点:
- 自由控制:JavaScript 动画能够更加自由地控制动画的速度、方向等,可以实现更加复杂的动画效果。
- 兼容性好:由于 JavaScript 是浏览器通用的语言,因此在实现动画效果时,能够更好地兼容不同的浏览器。
- 可维护性强:使用 JavaScript 实现动画时,代码结构更加灵活,能够更好地维护和扩展。
缺点:
- 资源占用高:JavaScript 动画通常需要更多的 CPU 和内存资源,因此在实现动画效果时需要考虑系统资源的消耗问题。
- 性能问题:JavaScript 动画性能受 JavaScript 引擎的影响,而不是浏览器引擎,因此需要对代码进行优化以提高动画性能。
- 复杂度高:JavaScript 动画的实现复杂度通常比 CSS 动画高,因此需要对动画效果进行设计和规划。
题目二
JS 中怎么阻止事件冒泡和事件默认行为?
在 JavaScript 中,可以通过以下方式阻止事件的冒泡和默认行为:
阻止事件冒泡:事件冒泡是指当一个子元素触发了某个事件后,事件会一直冒泡到它的父元素,直到到达文档根节点。为了阻止事件冒泡,可以使用事件对象的 stopPropagation() 方法。例如:
document.getElementById("child").addEventListener("click", function(event) {
// 阻止事件冒泡
event.stopPropagation();
});
上面的代码中,当子元素被点击时,事件不会继续冒泡到父元素。
阻止事件默认行为:
事件的默认行为是指事件发生时,浏览器会默认执行的一些操作,例如提交表单、打开链接等。为了阻止事件的默认行为,可以使用事件对象的 preventDefault() 方法。例如:
document.getElementById("link").addEventListener("click", function(event) {
// 阻止链接的默认跳转行为
event.preventDefault();
});