滴滴 一面&二面

该博客总结了Java面试常见知识点,涵盖MySQL优化、TCP三次握手与四次挥手、用户态和内核态区别等内容。详细阐述了MySQL在硬件、架构、配置和SQL层面的优化方法,以及日志、事务特性和隔离级别等知识,还介绍了解决深度分页问题的策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本人是努力的26届在校努力学习的程序员,努力学习开发,每天按照自己的学习和答案,总结全网最新的面经,大家可以关注一下,一起努力,打破信息差,找到满意工作

目录

1.说一下MySQL 优化有哪几方面

三次握手

为什么要三次握手?

四次挥手

为什么断开连接需要四次挥手?

从输入URL到页面发生了什么

为什么要有用户态和内核态?只有一个内核态不行么?

用户态和内核态是如何切换的?

5.线程和进程的区别

有了进程为什么还需要线程?

6.HashSet和HashMap的区别和实现原理

HashMap 和 TreeMap 区别

7.Sychoronized和Volatile的区别和解决了什么

8.synchronized的锁升级过程

9.Synchronized是公平锁吗,ReetrantLock是怎么实现公平锁

10Java中对象的创建过程

1.类加载检查

11垃圾回收的过程

12CHAR和VARCHAR有什么区别

索引的优缺点

14介绍一下日志

15redolog如何保证持久性

16能不能只用binLog不用redolog

17ACID特性

18四种事务隔离级别

19如何解决深度分页的问题


1.说一下MySQL 优化有哪几方面

MySQL 的性能优化我认为可以分为 4 大部分

l 硬件和操作系统层面的优化

l 架构设计层面的优化

l MySQL 程序配置优化

l SQL 优化

从硬件层面来说,影响 Mysql 性能的因素有,CPU、可用内存大小、磁盘读写速度、

网络带宽从操作系层面来说,应用文件句柄数、操作系统网络的配置都会影响到 Mysql 性能。 这部分的优化一般由 DBA 或者运维工程师去完成。

架构设计层面的优化

MySQL 是一个磁盘 IO 访问量非常频繁的关系型数据库

在高并发和高性能的场景中.MySQL 数据库必然会承受巨大的并发压力,而此时,我们

的优化方式可以分为几个部分。

1. 搭建 Mysql 主从集群,单个 Mysql 服务容易单点故障,一旦服务器宕机,将会导

致依赖 Mysql 数据库的应用全部无法响应。 主从集群或者主主集群可以保证服务

的高可用性。

2. 读写分离设计,在读多写少的场景中,通过读写分离的方案,可以避免读写冲突导

致的性能影响

3. 引入分库分表机制,通过分库可以降低单个服务器节点的 IO 压力,通过分表的方

式可以降低单表数据量,从而提升 sql 查询的效率。

4. 针对热点数据,可以引入更为高效的分布式数据库,比如 Redis、MongoDB 等,

他们可以很好的缓解 Mysql 的访问压力,同时还能提升数据检索性能

MySQL 程序配置优化

MySQL 是一个经过互联网大厂验证过的生产级别的成熟数据库,对于 Mysql 数据库本 身的优化,一般是通过 Mysql 中的配置文件 my.cnf 来完成的,比如。

Mysql5.7 版本默认的最大连接数是 151 个,这个值可以在 my.cnf 中修改。

binlog 日志,默认是不开启

缓存池 bufferpoll 的默认大小配置等。

由于这些配置一般都和用户安装的硬件环境以及使用场景有关系,因此这些配置官方只

会提供一个默认值,具体情况还得由使用者来修改。

关于配置项的修改,需要关注两个方面。

l 配置的作用域,分为会话级别和全局

l 是否支持热加载

因此,针对这两个点,我们需要注意的是:

l 全局参数的设定对于已经存在的会话无法生效

l 会话参数的设定随着会话的销毁而失效

l 全局类的统一配置建议配置在默认配置文件中,否则重启服务会导致配置失效

SQL 优化

SQL 优化又能分为三步曲

l 第一、慢 SQL 的定位和排查

我们可以通过慢查询日志和慢查询日志分析工具得到有问题的 SQL 列表。

l 第二、执行计划分析

针对慢 SQL,我们可以使用关键字 explain 来查看当前 sql 的执行计划.可以重点关注

type key rows filterd 等字段 ,从而定位该 SQL 执行慢的根本原因。再有的放矢的进 行优化

l 第三、使用 show profile 工具

Show Profile 是 MySQL 提供的可以用来分析当前会话中,SQL 语句资源消耗情况的 工具,可用于 SQL 调优的测量。在当前会话中.默认情况下处于 show profile 是关闭状 态,打开之后保存最近 15 次的运行结果

针对运行慢的 SQL,通过 profile 工具进行详细分析.可以得到 SQL 执行过程中所有的 资源开销情况. 如 IO 开销,CPU 开销,内存开销等.

以上就是我对 MySQL 性能优化的理解。

  1. TCP三次握手和四次挥手

1. TCP 协议,是一种可靠的,基于字节流的,面向连接的传输层协议。

¢ 可靠性体现在 TCP 协议通信双方的数据传输是稳定的,即便是在网络不好的情

况下,TCP 都能够保证数据传输到目标端,而这个可靠性是基于数据包确认机

制来实现的。

¢ TCP 通信双方的数据传输是通过字节流来实现传输的

¢ 面向连接,是说数据传输之前,必须要建立一个连接,然后基于这个连接进行

数据传输

2. 因为 TCP 是面向连接的协议,所以在进行数据通信之前,需要建立一个

可靠的连接,TCP 采用了三次握手的方式来实现连接的建立

三次握手

  1. 第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。
  2. 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
  3. 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。

为什么要三次握手?

三次握手的意义在于确定双方都能够完成读写操作。

第一次握手,客户端发了个连接请求消息到服务端,服务端收到信息后知道自己与客户端是可以连接成功的,但此时客户端并不知道服务端是否已经接收到了它的请求,所以服务端接收到消息后的应答。客户端得到服务端的反馈后,才确定自己与服务端是可以连接上的,这就是第二次握手。而服务端发送出去的消息,要等客户端响应后,才能确定此次连接为有效连接。

四次挥手

在完成数据交互之后,如果选择关闭连接,以回收资源,则完成四次挥手来进行“和平分手”。

  1. 第一次挥手:主动关闭方发送第一个包,其中FIN标志位为1,发送顺序号seq为X。
  2. 第二次挥手:被动关闭方收到FIN包后发送第二个包,其中发送顺序号seq为Z,接收顺序号ack为X+1。
  3. 第三次挥手:被动关闭方再发送第三个包,其中FIN标志位为1,发送顺序号seq为Y,接收顺序号ack为X。
  4. 第四次挥手:主动关闭方发送第四个包,其中发送顺序号为X,接收顺序号为Y。至此,完成四次挥手。

为什么断开连接需要四次挥手?

三次握手是因为建立连接时,ACK和SYN可以放在一个报文里来发送。而关闭连接时,被动关闭方可能还需要发送一些数据后,再发送FIN报文表示同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。因此断开连接需要4次。

  1. 从输入URL到页面发生了什么

总体来说分为以下几个步骤:

  1. 在浏览器中输入指定网页的 URL。
  2. 浏览器通过 DNS 协议,获取域名对应的 IP 地址。
  3. 浏览器根据 IP 地址和端口号,向目标服务器发起一个 TCP 连接请求。
  4. 浏览器在 TCP 连接上,向服务器发送一个 HTTP 请求报文,请求获取网页的内容。
  5. 服务器收到 HTTP 请求报文后,处理请求,并返回 HTTP 响应报文给浏览器。
  6. 浏览器收到 HTTP 响应报文后,解析响应体中的 HTML 代码,渲染网页的结构和样式,同时根据 HTML 中的其他资源的 URL(如图片、CSS、JS 等),再次发起 HTTP 请求,获取这些资源的内容,直到网页完全加载显示。
  7. 浏览器在不需要和服务器通信时,可以主动关闭 TCP 连接,或者等待服务器的关闭请求。

上图有一个错误需要注意:是 OSPF 不是 OPSF。 OSPF(Open Shortest Path First,ospf)开放最短路径优先协议, 是由 Internet 工程任务组开发的路由选择协议

  1. 用户态和内核态的区别

根据进程访问资源的特点,我们可以把进程在系统上的运行分为两个级别:

  • 用户态(User Mode) : 用户态运行的进程可以直接读取用户程序的数据,拥有较低的权限。当应用程序需要执行某些需要特殊权限的操作,例如读写磁盘、网络通信等,就需要向操作系统发起系统调用请求,进入内核态。
  • 内核态(Kernel Mode):内核态运行的进程几乎可以访问计算机的任何资源包括系统的内存空间、设备、驱动程序等,不受限制,拥有非常高的权限。当操作系统接收到进程的系统调用请求时,就会从用户态切换到内核态,执行相应的系统调用,并将结果返回给进程,最后再从内核态切换回用户态。

内核态相比用户态拥有更高的特权级别,因此能够执行更底层、更敏感的操作。不过,由于进入内核态需要付出较高的开销(需要进行一系列的上下文切换和权限检查),应该尽量减少进入内核态的次数,以提高系统的性能和稳定性。

为什么要有用户态和内核态?只有一个内核态不行么?

  • 在 CPU 的所有指令中,有一些指令是比较危险的比如内存分配、设置时钟、IO 处理等,如果所有的程序都能使用这些指令的话,会对系统的正常运行造成灾难性地影响。因此,我们需要限制这些危险指令只能内核态运行。这些只能由操作系统内核态执行的指令也被叫做 特权指令 。
  • 如果计算机系统中只有一个内核态,那么所有程序或进程都必须共享系统资源,例如内存、CPU、硬盘等,这将导致系统资源的竞争和冲突,从而影响系统性能和效率。并且,这样也会让系统的安全性降低,毕竟所有程序或进程都具有相同的特权级别和访问权限。

因此,同时具有用户态和内核态主要是为了保证计算机系统的安全性、稳定性和性能。

用户态和内核态是如何切换的?

用户态切换到内核态的 3 种方式:

  1. 系统调用(Trap):用户态进程 主动 要求切换到内核态的一种方式,主要是为了使用内核态才能做的事情比如读取磁盘资源。系统调用的机制其核心还是使用了操作系统为用户特别开放的一个中断来实现。
  2. 中断(Interrupt):当外围设备完成用户请求的操作后,会向 CPU 发出相应的中断信号,这时 CPU 会暂停执行下一条即将要执行的指令转而去执行与中断信号对应的处理程序,如果先前执行的指令是用户态下的程序,那么这个转换的过程自然也就发生了由用户态到内核态的切换。比如硬盘读写操作完成,系统会切换到硬盘读写的中断处理程序中执行后续操作等。
  3. 异常(Exception):当 CPU 在执行运行在用户态下的程序时,发生了某些事先不可知的异常,这时会触发由当前运行进程切换到处理此异常的内核相关程序中,也就转到了内核态,比如缺页异常。

在系统的处理上,中断和异常类似,都是通过中断向量表来找到相应的处理程序进行处理。区别在于,中断来自处理器外部,不是由任何一条专门的指令造成,而异常是执行当前指令的结果。

5.线程和进程的区别

·  进程(Process) 是指计算机中正在运行的一个程序实例。举例:你打开的微信就是一个进程。

·  线程(Thread) 也被称为轻量级进程,更加轻量。多个线程可以在同一个进程中同时执行,并且共享进程的资源比如内存空间、文件句柄、网络连接等。举例:你打开的微信里就有一个线程专门用来拉取别人发你的最新的消息

·  线程是进程划分成的更小的运行单位,一个进程在其执行的过程中可以产生多个线程。

·  线程和进程最大的不同在于基本上各进程是独立的,而各线程则不一定,因为同一进程中的线程极有可能会相互影响。

·  线程执行开销小,但不利于资源的管理和保护;而进程正相反。

有了进程为什么还需要线程?

  • 进程切换是一个开销很大的操作,线程切换的成本较低。
  • 线程更轻量,一个进程可以创建多个线程。
  • 多个线程可以并发处理不同的任务,更有效地利用了多处理器和多核计算机。而进程只能在一个时间干一件事,如果在执行过程中遇到阻塞问题比如 IO 阻塞就会挂起直到结果返回。
  • 同一进程内的线程共享内存和文件,因此它们之间相互通信无须调用内核。

6.HashSet和HashMap的区别和实现原理

HashSet 底层就是基于 HashMap 实现的

以下是他们的区别

HashMap 和 TreeMap 区别

TreeMap 和HashMap 都继承自AbstractMap ,但是需要注意的是TreeMap它还实现了NavigableMap接口和SortedMap 接口。

相比于HashMap来说, TreeMap 主要多了对集合中的元素根据键排序的能力以及对集合内元素的搜索的能力。

7.Sychoronized和Volatile的区别和解决了什么

synchronized 关键字和 volatile 关键字是两个互补的存在,而不是对立的存在!

  • volatile 关键字是线程同步的轻量级实现,所以 volatile性能肯定比synchronized关键字要好 。但是 volatile 关键字只能用于变量而 synchronized 关键字可以修饰方法以及代码块 。
  • volatile 关键字能保证数据的可见性,但不能保证数据的原子性。synchronized 关键字两者都能保证。
  • volatile关键字主要用于解决变量在多个线程之间的可见性,而 synchronized 关键字解决的是多个线程之间访问资源的同步性

8.synchronized的锁升级过程

在 jdk1.6 版本中,synchronized 增加了锁升级的机制,来平衡数据安全性和性能。

简单来说,就是线程去访问 synchronized 同步代码块的时候,synchronized 根

线程竞争情况,会先尝试在不加重量级锁的情况下去保证线程安全性。所以引入了偏向 锁和轻量级锁的机制。 偏向锁,就是直接把当前锁偏向于某个线程,简单来说就是通过 CAS 修改偏向锁标记, 这种锁适合同一个线程多次去申请同一个锁资源并且没有其他线程竞争的场景。 轻量级锁也可以称为自旋锁,基于自适应自旋的机制,通过多次自旋重试去竞争锁。自旋锁优点在于它避免避免了用户态到内核态的切换带来的性能开销。

Synchronized 引入了锁升级的机制之后,如果有线程去竞争锁:

首先,synchronized 会尝试使用偏向锁的方式去竞争锁资源,如果能够竞争到偏

向锁,表示加锁成功直接返回。如果竞争锁失败,说明当前锁已经偏向了其他线程。

需要将锁升级到轻量级锁,在轻量级锁状态下,竞争锁的线程根据自适应自旋次数

去尝试抢占锁资源,如果在轻量级锁状态下还是没有竞争到锁,

就只能升级到重量级锁,在重量级锁状态下,没有竞争到锁的线程就会被阻塞,线

程状态是 Blocked。 处于锁等待状态的线程需要等待获得锁的线程来触发唤醒

总的来说, Synchronized 的锁升级的设计思想,在我看来本质上是一种性能和安全性的平衡,也就是如何在不加锁的情况下能够保证线程安全性。

9.Synchronized是公平锁吗,ReetrantLock是怎么实现公平锁

不是

ReentrantLock 比 synchronized 增加了一些高级功能

相比synchronized,ReentrantLock增加了一些高级功能。主要来说主要有三点:

等待可中断 : ReentrantLock提供了一种能够中断等待锁的线程的机制,通过 lock.lockInterruptibly() 来实现这个机制。也就是说正在等待的线程可以选择放弃等待,改为处理其他事情。

可实现公平锁 : ReentrantLock可以指定是公平锁还是非公平锁。而synchronized只能是非公平锁。所谓的公平锁就是先等待的线程先获得锁。ReentrantLock默认情况是非公平的,可以通过 ReentrantLock类的ReentrantLock(boolean fair)构造方法来指定是否是公平的。

可实现选择性通知(锁可以绑定多个条件): synchronized关键字与wait()和notify()/notifyAll()方法相结合可以实现等待/通知机制。ReentrantLock类当然也可以实现,但是需要借助于Condition接口与newCondition()方法。

10Java中对象的创建过程

1.类加载检查

虚拟机遇到一条 new 指令时,首先将去检查这个指令的参数是否能在常量池中定位到这个类的符号引用,并且检查这个符号引用代表的类是否已被加载过、解析和初始化过。如果没有,那必须先执行相应的类加载过程

分配内存

在类加载检查通过后,接下来虚拟机将为新生对象分配内存。对象所需的内存大小在类加载完成后便可确定,为对象分配空间的任务等同于把一块确定大小的内存从 Java 堆中划分出来。分配方式有 “指针碰撞” 和 “空闲列表” 两种,选择哪种分配方式由 Java 堆是否规整决定,而 Java 堆是否规整又由所采用的垃圾收集器是否带有压缩整理功能决定。

初始化零值

内存分配完成后,虚拟机需要将分配到的内存空间都初始化为零值(不包括对象头),这一步操作保证了对象的实例字段在 Java 代码中可以不赋初始值就直接使用,程序能访问到这些字段的数据类型所对应的零值。

设置对象头

初始化零值完成之后,虚拟机要对对象进行必要的设置,例如这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的 GC 分代年龄等信息。 这些信息存放在对象头中。 另外,根据虚拟机当前运行状态的不同,如是否启用偏向锁等,对象头会有不同的设置方式。

执行init方法

在上面工作都完成之后,从虚拟机的视角来看,一个新的对象已经产生了,但从 Java 程序的视角来看,对象创建才刚开始,<init> 方法还没有执行,所有的字段都还为零。所以一般来说,执行 new 指令之后会接着执行 <init> 方法,把对象按照程序员的意愿进行初始化,这样一个真正可用的对象才算完全产生出来

11垃圾回收的过程

12CHAR和VARCHAR有什么区别

第一个,char 是一个固定长度的字符串,Varchar 是一个可变长度的字符串

假设声明一个 char(10)的长度,如果存储字符串“abc”,虽然实际字符长度只有 3,

但是 char 还是会占 10 个字节长度。

同样,如果用 varchar 存储,那它只会使用 3 个字符的实际长度来存储。

l 第二个,存储的效率不同,char 类型每次修改以后存储空间的长度不变,所以效率 更高 varchar 每次修改数据都需要更新存储空间长度,效率较低

l 第三个,存储空间不同,char 不管实际数据大小,存储空间是固定的,而 varchar

存储空间等于实际数据长度, 所以 varchar 实际存储空间的使用要比 char 更小

基于他们特性的分析,可以得出一个基本的结论:

l char 适合存储比较短的且是固定长度的字符串

l varchar 适合存储可变长度的字符串

  1. 介绍一下索引

索引是一种用于快速查询和检索数据的数据结构,其本质可以看成是一种排序好的数据结构。

索引的作用就相当于书的目录。打个比方: 我们在查字典的时候,如果没有目录,那我们就只能一页一页的去找我们需要查的那个字,速度很慢。如果有目录了,我们只需要先去目录里查找字的位置,然后直接翻到那一页就行了。索引底层数据结构存在很多种类型,常见的索引结构有: B 树, B+树 和 Hash、红黑树。在 MySQL 中,无论是 Innodb 还是 MyIsam,都使用了 B+树作为索引结构

索引的优缺点

优点

  • 使用索引可以大大加快数据的检索速度(大大减少检索的数据量), 减少 IO 次数,这也是创建索引的最主要的原因。
  • 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。

缺点

  • 创建索引和维护索引需要耗费许多时间。当对表中的数据进行增删改的时候,如果数据有索引,那么索引也需要动态的修改,会降低 SQL 执行效率。
  • 索引需要使用物理文件存储,也会耗费一定空间。

但是,使用索引一定能提高查询性能吗?

大多数情况下,索引查询都是比全表扫描要快的。但是如果数据库的数据量不大,那么使用索引也不一定能够带来很大提升。

14介绍一下日志

MySQL 日志 主要包括错误日志、查询日志、慢查询日志、事务日志、二进制日志几大类。其中,比较重要的还要属二进制日志 binlog(归档日志)和事务日志 redo log(重做日志)和 undo log(回滚日志)

具体

MySQL三大日志(binlog、redo log和undo log)详解 | JavaGuide

15redolog如何保证持久性

1.记录修改操作:当数据发生修改时,不是直接修改数据,而是在Redo log中先记录本次操作。这个操

作是顺序写入的,速度非常快。

2.数据修改:在Redo log中记录操作后,再修改缓冲区中的数据。这一步是实际的数据修改

3.日志刷盘:在事务提交时或者提交前,通过调用fsync接口将Redo log写入磁盘。这一步是为了确保

在数据库系统发生故障时,已经记录的修改操作不会丢失。

4.故障恢复:如果数据库系统发生故障并宕机,那么在重启时,系统会读取Redo log中的数据,根据这些日志对数据库进行恢复。由于Redo log是预写日志,它记录了所有已经提交的事务的修改操作,因此可以用来恢复数据库到一致的状态。通过这种方式,Redo log保证了即使在数据库系统发生故障并宕机的情况下,已经提交的事务的修改也不会丢失,从而满足了持久性的要求。同时,由于Redo log的顺序写入和快速恢复的特性,它也在一定程度上提高了数据库系统的性能。

16能不能只用binLog不用redolog

不能只用binlog而不用redo log。虽然binlog和redo log都是用于保证数据库持久性的重要机制,但它各自的作用和用途是不同的。

binlog(二进制日志)主要用于记录数据库的所有更改,包括数据修改和表结构变更等。它可以用于数据恢复和主从复制等场景。然而,binlog并不具备崩渍恢复的能力,也就是说,它不能单独用于在系统崩渍后恢复数据。

而redo log(重做日志)则主要用于保证事务的持久性。在数据库事务提交前,相关的修改操作会先写入redo log中,并在系统崩渍后利用这些日志来恢复数据。这样可以确保即使系统发生故障,已经提交的事务的修改也不会丢失。

因此,虽然binlog和redo log都是数据库持久性的重要保障,但它们各自的作用和用途是不同的。在实际应用中,通常会将它们结合使用,以确保数据库的特久性和可靠性。如果只使用binlog而不使用redo log,那么在系统崩渍后可能无法恢复已经提交的事务的修改,从而导致数据丢失。

17ACID特性

·  原子性(Atomicity):事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;

·  一致性(Consistency):执行事务前后,数据保持一致,例如转账业务中,无论事务是否成功,转账者和收款人的总额应该是不变的;

·  隔离性(Isolation):并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的;

·  持久性(Durability):一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。

18四种事务隔离级别

SQL 标准定义了四个隔离级别:

  • READ-UNCOMMITTED(读取未提交) :最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
  • READ-COMMITTED(读取已提交) :允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
  • REPEATABLE-READ(可重复读) :对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
  • SERIALIZABLE(可串行化) :最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。

MySQL InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ(可重读)

从上面对 SQL 标准定义了四个隔离级别的介绍可以看出,标准的 SQL 隔离级别定义里,REPEATABLE-READ(可重复读)是不可以防止幻读的。

但是!InnoDB 实现的 REPEATABLE-READ 隔离级别其实是可以解决幻读问题发生的,主要有下面两种情况:

  • 快照读:由 MVCC 机制来保证不出现幻读。
  • 当前读:使用 Next-Key Lock 进行加锁来保证不出现幻读,Next-Key Lock 是行锁(Record Lock)和间隙锁(Gap Lock)的结合,行锁只能锁住已经存在的行,为了避免插入新行,需要依赖间隙锁。

因为隔离级别越低,事务请求的锁越少,所以大部分数据库系统的隔离级别都是 READ-COMMITTED ,但是你要知道的是 InnoDB 存储引擎默认使用 REPEATABLE-READ 并不会有任何性能损失。

InnoDB 存储引擎在分布式事务的情况下一般会用到 SERIALIZABLE 隔离级别。

  1. update语句的具体执行流程

1.解析(Parsing):

客户端发送[PDATE语句到服务器。

服务器对SQL语句进行语法解析,生成解析树。

进行语义检查,例如检查表和列名是否存在,权限是否足够等。

2.预处理(Preprocessing):

生成执行计划(Execution Plan)。优化器会决定如何高效地执行这个PDATE语句,例如选择哪

个索引,如何进行数据查找等。

确定影凯响的行数,这会影响到后续操作(如锁的数量)。

3.锁定(Locking):

根据优化器生成的执行计,确定需要锁定哪些行或表。

如果是InnoDB存储擎,它会在事务开始时使用行锁或表锁来确保数据的一致性。

4.执行(Execution):

根据解析和预处理的结果,开始实际的数据更新操作。

遍历每一行(或者通过索引直接定位到某些行),应用PDATE语句中的修改。

对于每一行,MySQL会先检查该行是否满足PDATE语句的WHERE条件,如果满足则进行更新。

5.写入redo log(如果是InnoDB):

在数据实际更新到磁盘之前,InnoDB会先将这个更新操作记泉到redo log中。

redo log是循环写的,当达到一定大小时会从头开始写。

6.更新数据页(如果是InnoDB):

将数据实际更新到内存中的缓冲池中。

如果这个修改导致数据页变得不整洁(比如半满或者混合了新旧版本的数据),可能会触发页合并或者页分裂的操作。

7.写入binlog(如果是配置了的话):

将这次UPDATE操作的信息写入到binlog中。

binlog是MySQL用于复制和恢复的数据日志。

8.提交事务(Commit):

如果[PDATE语句在事务中执行,那么在所有的更新操作都成功之后,事务会被提交。

在事务提交时,M小ySQL会将redo log和binlog都刷新到磁盘上,确保数据的持久性。

如果使用了两阶段提交协议,在提交阶段还会进行额砂外的检查和日志写入。

9.返回结果:

客户端接收更新操作的结果,包括更新的行数等信息。

10.清理(Cleanup):

释放相关的锁和资源。

  1. 如果有一个字段是status值为0或者1,适合建索引吗

假设表中有一千万条记录,某个状态为0的记录总数大概有100条,那么你想查询状态为0的记录时,有没有索引影响非常大,而查询状态为1的记录,则索引基本无用。如果两种状态的记录数相差无几的话,索引也基本无用

假设表中有一千万条记录,某个状态为0的记录总数大概会有100条,就在这个状态列建立索引其他两种情况不需要建立索引,毕竟索引空间消耗不小的

19如何解决深度分页的问题

遇到的问题:因为我们拿到的是我们校医院患者数据,数据量比较大,所以患者表深分页的问题 深分页就是 mysql的limit关键字 ,limit关键字需要设置偏移量和他查询的条数进行分页,如果limit的偏移量数值设置的比较大,他还要扫描偏移量的全部数据然后舍弃掉。比如 limit 1000 10,它需要扫描1010条数据并且丢弃掉前面的1000条,只返回最后的10条,首先想着是设置避免直接查询太深的页码,让偏移量少一点,不设置跳转的功能,但是觉得可能体验不太好,所以就想着从sql上做优化,上网搜索了一下,主要有两种方法一就是要记录上一次查询到哪了,这一次就筛选掉之前的数据,减少limit的丢弃量,那么知道上次分页的最后一个数据的id并且id是自增的,那就可以根据id筛选掉不需要的数据,偏移量直接不写,只需要具体的条数就可以了,比如select from table where id>? and 其他条件 limit ?,第二种就是id不是自增的,就利用子查询,只查询id作为外部查询的id in的条件,通过索引覆盖减少回表,从而尽可能提升查询效率 比如 select from table where id in (select id from (select id from table where 条件 limit ?,?)t),我们这个项目用的是第二种方式

  1. redis的zset底层是怎么实现的

Redis 5 种基本数据类型详解 | JavaGuide

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值