Java高级开发高频面试题(三)

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: Java高级开发高频面试题

🍊 原子性底层实现原理(undo log日志 )

原子性是指一个操作要么全部执行成功,要么全部执行失败,不存在部分执行的情况。在数据库底层实现中,为了保证事务的原子性,通常采用undo log日志来实现原子性,记录事务执行前的数据状态,以便在发生错误或者回滚时恢复数据原始状态。Undo log日志记录了数据库操作的所有细节,包括修改的数据和修改前的值。

具体的实现原理如下:

  1. 在事务执行之前,先将需要修改的数据放入buffer pool中的内存页中,并将修改前的数据复制一份放入undo log中。
  2. 事务执行时,将对应的数据进行修改,并将修改后的数据记录到redo log中。
  3. 如果事务执行成功,则将redo log中的数据更新到磁盘上的数据文件中。同时将undo log中的数据删除或者标记为已提交。
  4. 如果事务执行失败或者需要回滚,则从undo log中读取修改前的数据,恢复原始数据状态。

举个例子:假设用户要将某个账户的余额从100元增加到200元,系统执行以下步骤:

  1. 记录当前余额为100元。
  2. 在缓存区中将余额增加到200元。
  3. 等待操作确认。
  4. 操作确认,提交缓存区中的数据。
  5. 完成。

如果在第3步或第4步发生异常,系统会根据undo log日志将缓存区中的余额恢复为100元,保证操作的原子性。

🍊 一致性底层实现原理

MySQL的一致性是指在多线程并发访问数据库时,数据始终保持一致的状态。

实现一致性的方式主要包括以下方面:

🎉 1. 事务机制

MySQL通过事务机制来保证数据一致性。事务是指一组操作序列,这些操作要么都执行成功,要么全部撤回,保证数据的完整性和一致性。在MySQL中,通过使用事务来对数据进行读写操作,可以保证数据的一致性。

🎉 2. 锁机制

MySQL通过锁机制来保证数据一致性。

当多个线程同时对同一数据进行读写操作时,可能会出现数据不一致的情况,比如一个线程在修改数据的过程中,另一个线程也读取了这些数据,导致了数据的不一致。为了解决这个问题,MySQL引入了锁机制。

锁是一种保护机制,可以防止多个线程同时对同一数据进行读写操作,影响数据的一致性。锁分为共享锁和排他锁,共享锁允许多个事务并发读取同一数据行,但不允许写入;排他锁则只允许一个事务读取或写入数据行。MySQL采用多粒度锁定机制,即对各层级的数据对象(如行、表、页)进行锁定,从而实现细粒度的数据访问控制。

举个例子来说,假如有三个线程同时要访问同一张表,第一个线程要进行写操作,第二个线程要进行读操作,第三个线程要进行写操作。这时候MySQL就会根据锁的机制将这些线程进行分配,第一个线程会被授予排他锁,第二个线程会被授予共享锁,第三个线程也会被授予排他锁。这样就可以保证在同一时间内,只有一个线程能够对表中的数据进行写操作,避免了数据的不一致。

🎉 3. 隔离级别

MySQL 支持多种隔离级别,如读未提交、读已提交、可重复读和串行化,可以根据情况选择适当的隔离级别以确保数据的一致性。如果应用需要高度的数据一致性,可以选择可重复读或串行化隔离级别;如果应用对数据一致性要求较低,可以选择读已提交隔离级别;如果应用对性能要求较高,可以选择读未提交隔离级别。

🎉 4. MVCC

多版本并发控制(MVCC)是一种用于在多个事务同时访问同一个数据时保证数据一致性的技术。MySQL 使用 MVCC 机制来避免数据的读写冲突,确保数据的一致性。

在MVCC中,每个事务看到的数据都是独立的版本,这些版本是在事务开始之前生成的。这意味着在多个事务同时访问同一个数据时,每个事务都能看到自己的版本,而不会影响到其他事务的数据。MySQL使用两种方式来实现MVCC,一种是乐观锁,一种是悲观锁。在MVCC中,读操作可以不加锁,不会对其他事务造成阻塞,而写操作则需要加锁。

乐观锁机制是指事务在进行读操作时,只会复制数据的快照版本,而不是实际的数据版本。因此,当多个事务同时读取数据时,每个事务都可以看到自己的版本,而不会影响其他事务的读取。在写入数据时,MySQL会为写入的数据生成一个新版本,在写入之前会检查该数据是否被其他事务修改过,如果有,则会回滚该事务,再次尝试写入。这种机制可以有效地减少锁冲突,提高并发性能。在读操作较多、写操作较少的场景下,或者在对于数据一致性要求不高但是需要没有脏写问题的场景下,使用乐观锁能够提高并发性能。

悲观锁机制则是在读写操作时,直接对数据进行加锁,其他事务需要等待锁被释放才能进行操作。这种机制会对并发性能造成一定的影响,但可以确保数据的一致性。数据一致性要求较高的场景下,或者在写操作较多、读操作较少、写操作时间较长的场景下,悲观锁可以避免读操作和写操作的冲突。

MySQL使用MVCC机制来避免数据的读写冲突,确保数据的一致性。通过生成数据的快照版本和加锁机制的处理,可以有效地提高并发性能,保证数据的安全性和一致性。

MySQL 通过使用多种技术和机制来确保数据的一致性,从而保证了数据的可靠性。

🍊 持久性底层实现原理(redo log机制)

持久性是指在数据库系统中,当一个事务提交后,该事务所做的更改操作必须被永久保存在数据库中,不能因为系统故障或其他原因而丢失。Redo log机制是一种常见的实现持久性的方式。将对数据的修改操作记录在一个日志文件中,并在每一次操作之后将该日志文件强制刷入到磁盘中,以保证即使在数据库系统发生崩溃时,也能从日志文件中恢复数据的一致性。

底层实现原理是:redo log机制是由InnoDB存储引擎实现的,mysql 的数据是存放在这个磁盘上的,但是每次去读数据都需要通过这个磁盘io,效率就很低。InnoDB存储引擎将每个事务的修改操作记录在一个称为redo log的循环缓冲区buffer中,这个 buffer 中包含了磁盘部分数据页的一个映射,作为访问数据库的一个缓冲,从数据库读取一个数据,就会先从这个 buffer 中获取,如果 buffer 中没有,就从这个磁盘中获取,读取完再放到这个 buffer 缓冲中,当数据库写入数据的时候,也会首先向这个 buffer 中写入数据,定期将 buffer 中的数据刷新到磁盘中,进行持久化的一个操作。如果 buffer 中的数据还没来得及同步到这个磁盘上,这个时候 MySQL 宕机了,buffer 里面的数据就会丢失,造成数据丢失的情况,持久性就无法保证了。使用 redolog 解决这个问题,当数据库的数据要进行新增或者是修改的时候,除了修改这个 buffer 中的数据,还会把这次的操作写入到这个 redolog 中,如果 msyql 宕机了,就可以通过 redolog 去恢复数据,redolog 是预写式日志,会先将所有的修改写入到日志里面,然后再更新到 buffer 里面,让这个数据不会丢失,保证了数据的持久性。另外,redo log缓冲区的大小是可配置的,一旦缓冲区被填满,InnoDB存储引擎就会将缓冲区中的内容刷新到磁盘上的redo log文件中,并在记录日志前将缓冲区中的数据刷入到磁盘中。

InnoDB存储引擎还将每个数据页的修改操作也记录在了对应的redo log文件中。在进行数据恢复时,InnoDB存储引擎会首先将已提交的事务的redo log从redo log文件中读取出来,然后通过redo log中的信息对数据进行恢复操作。由两部分组成:一是内存中的重做日志缓冲,是易丢失的;二是重做日志文件,是持久的。

🍊 隔离性底层实现原理(MVCC多版本并发控制)

MVCC多版本并发控制可以保证数据的隔离性。它基于“多个版本”的概念,每个版本都有自己的时间戳。不同的事务同时执行时,它们会看到不同的数据版本,这样一个事务修改数据时,不会影响其他事务的读操作,而其他事务读取到的是之前的版本,而不是被修改后的版本。这也可以避免数据的“脏读”问题。

具体实现原理是:每个数据行会记录其修改的版本号(也称为“时间戳”)。当一个事务要读取某个数据行时,它会先检查该行的版本号和其开始时间进行比较,如果版本号大于等于该事务的开始时间,那么该事务就可以读取该数据行。如果小于该事务的开始时间,那么该数据行就不适合该事务读取,因为该数据行已经被其他事务修改过了。

当一个事务要修改某个数据行时,它会创建一个新版本,并将新版本的版本号设置为该事务的开始时间。然后,该事务执行修改操作,并在新版本中记录修改后的值。这个过程是原子性的,即修改操作要么全部成功,要么全部失败。当事务提交时,它会将新版本的版本号设为提交时间。

这样,其他事务在读取该数据行时,如果版本号小于等于它的开始时间,则可以读取该版本的值;如果版本号大于它的开始时间,则需要读取其他版本的值。通过这种方式,MVCC多版本并发控制实现了高效的隔离性,并且还能避免数据的“脏读”问题。

MySQL的底层实现原理涉及到写-写操作和写-读操作。对于写-写操作,MySQL采用加锁来保证并发控制,其原理和Java中的锁机制相同。而对于写-读操作,MySQL使用MVCC(多版本并发控制)机制,避免频繁加锁互斥来保证隔离性。

MVCC机制的实现基于两个机制:读取视图(read-view)和版本链(undo)比对机制。对于每个被修改的行数据,默认情况下,MySQL会保留修改前的数据undo回滚日志,并用两个隐藏字段trx_id和roll_pointer串联起来形成一个历史记录版本链。在可重复读隔离级别下,执行任何查询SQL都会生成当前事务的一致性视图read-view,即生成一个版本。该read-view视图在事务结束之前不会变化。而在读已提交隔离级别下,在每次执行查询SQL时,都会重新生成read-view视图,即每次select都会生成一个版本。

在执行查询时,MySQL会从版本链最新的数据开始,逐条与read-view做比对。如果当前事务的id小于数组里面最小的id,表示这个版本是已提交的事务生成的,数据可见;如果当前事务比已创建的最大事务id还要大,表示这个版本还没开启事务,数据不可见;如果当前事务id在最小事务id与最大事务id之间,则需要比对其他情况,如果这个版本是由还没提交的事务生成的,则数据不可见,否则数据可见。这样就能得到最终的快照结果,保证了隔离性。

对于删除操作,可以认为是update的特殊情况,会在版本链上复制最新的数据,并将trx_id修改为删除操作的trx_id,同时在该条记录的头信息(record header)里的(deleted_flag)标记位写上true,表示当前记录已经被删除。查询时,如果delete_flag标记位为true,说明记录已被删除,不返回数据。

需要注意的是,begin/start transaction 命令并不是一个事务的起点,在执行到这些命令之后的第一个修改操作InnoDB表的语句,事务才真正启动,才会向MySQL申请事务id,MySQL内部是严格按照事务的启动顺序来分配事务id的。

MVCC机制的实现通过read-view机制和undo版本链比对机制,使得不同的事务可以读取同一条数据在版本链上的不同版本数据,保证了并发控制和隔离性。

🍊 BufferPool缓存机制

mysql 的数据是存放在磁盘上的,但是每次去读数据都需要通过这个磁盘io,效率就很低,使用 innodb 提供了一个缓存 buffer,这个 buffer 中包含了磁盘部分数据页的一个映射,作为访问数据库的一个缓冲,从数据库读取一个数据,就会先从这个 buffer 中获取,如果 buffer 中没有,就从这个磁盘中获取,读取完再放到这个 buffer 缓冲中,当数据库写入数据的时候,也会首先向这个 buffer 中写入数据,定期将 buffer 中的数据刷新到磁盘中,进行持久化的一个操作。

BufferPool缓存是一个大小可调整的内存池,它由多个缓存页组成。每个缓存页的大小默认为16KB,可以根据需要进行调整。当MySQL服务器需要读取或写入数据时,它会将数据按照一定的规则存放在BufferPool缓存中。

在缓存中存储的数据会根据其使用频率进行淘汰。当缓存页的空间不够时,MySQL会根据LRU算法(最近最少使用)将最不常用的缓存页替换出来,以保证缓存中存储的数据总是最有用的。

通过使用BufferPool缓存机制,MySQL可以显著提高查询效率,减少磁盘I/O的次数,从而提高数据库的性能。

为什么Mysql不能直接更新磁盘上的数据而且设置这么一套复杂的机制来执行SQL了?

因为来一个请求就直接对磁盘文件进行随机读写,然后更新磁盘文件里的数据性能可能相当差。

因为磁盘随机读写的性能是非常差的,所以直接更新磁盘文件是不能让数据库抗住很高并发的。 Mysql这套机制看起来复杂,但它可以保证每个更新请求都是更新内存BufferPool,然后顺序写日志文件,同时还能保证各种异常情况下的数据一致性。 更新内存的性能是极高的,然后顺序写磁盘上的日志文件的性能也是非常高的,要远高于随机读写磁盘文件。 正是通过这套机制,才能让我们的MySQL数据库在较高配置的机器上每秒可以抗下几干的读写请求。

MySQL的BufferPool缓存机制可以提高数据库查询效率,但也有一些弊端:

  1. 内存使用过多:BufferPool缓存机制需要占用一定的内存空间,当数据库中数据量非常大时,会占用大量的内存空间,可能会导致系统内存不足。
  2. 热数据的维护:BufferPool缓存机制只能缓存最近访问的数据,对于长时间不访问或很少访问的数据,缓存效果并不理想,需要花费额外的时间和资源从磁盘中读取。
  3. 数据的一致性:如果缓存中的数据与磁盘上的数据不一致,可能会导致数据丢失或数据不一致的情况发生。
  4. 磁盘IO操作的影响:如果缓存中的数据过多,可能会影响磁盘IO操作的效率,导致系统负载增加,从而影响数据库的查询效率。
  5. 缓存命中率的限制:BufferPool缓存机制只能缓存一部分数据,无法保证所有的查询都能从缓存中获取数据,如果缓存命中率不高,查询效率仍然会受到影响。

🍊 主键自增长实现原理

MySQL 主键自增长的实现原理,其实涉及到数据库设计和计算机科学中的自动编号机制。通俗来讲,就是数据库在新增一条记录时,可以自动为该记录生成唯一的标识符,也就是主键值。下面我们来详细解释这个过程。

🎉 1. 定义自增长主键

在 MySQL 中定义一个自增长主键,需要使用 AUTO_INCREMENT 关键词。例如:

CREATE TABLE students (
    id INT NOT NULL AUTO_INCREMENT,
    name VARCHAR(30) NOT NULL,
    PRIMARY KEY (id)
);

这里的 id 列就是自增长主键,MySQL 会自动为它生成唯一的值。

🎉 2. 实现自增长

当插入一条新记录时,MySQL 会检查表结构中是否有自增长主键。如果有,会寻找当前最大的主键值,然后在此基础上加 1,生成新的主键值。这个过程是在内存中完成的,速度非常快。

在InnoDB存储引擎的内存结构中,对每个含有自增长值的表都有一个自增长计数器。当对含有自增长的计数器的表进行插入操作时,这个计数器会被初始化。插入操作会依据这个自增长的计数器值加1赋予自增长列。这个实现方式称做AUTO-INC Locking。

这种锁其实是采用一种特殊的表锁机制,为了提高插入的性能,锁不是在一个事务完成后才释放,而是在完成对自增长值插入的SQL语句后立即释放。

虽然AUTO-INCLocking从一定程度上提高了并发插入的效率,但还是存在一些性能上的问题。

首先,对于有自增长值的列的并发插入性能较差,事务必须等待前一个插入的完成(虽然不用等待事务的完成)。

其次,对于 INSERT…SELECT的大数据量的插入会影响插入的性能,因为另一个事务中的插入会被阻塞。

从MySQL5.1.22版本开始,InnoDB存储引擎中提供了一种轻量级互斥量的自增长实现机制,这种机制大大提高了自增长值插入的性能。并且从该版本开始,InnoDB存储引擎提供了一个参数innodb_autoinc_lock_mode来控制自增长的模式,该参数的默认值为1。

innodb_autoinc_lock_mode有三个选项:

0:是mysql5.1.22版本之前自增长的实现方式,通过表锁的AUTO-INCLocking方式实现的。

1:是默认值,对于简单的插入(插入之前就可以确定插入的行数),这个值会用互斥量去对内存中的计数器进行累加操作。对于批量插入(插入之前就不确定插入的行数),还是通过表锁的AUTO-INCLocking方式实现。在这种配置下,如果不考虑回滚操作,对于自增值的列,它的增长还是连续的。区别在于如果使用了AUTO-INCLocking方式去产生自增长的值,这个时候再进行简单插入操作,就需要等待AUTO-INCLocking释放。

2:在这个模式下,对于所有的插入的语句,它自增长值的产生都是通过互斥量,不是通过AUTO-INCLocking方式,这是性能最高的方式,但是如果是并发插入,在每次插入的时候,自增长的值就不是连续的,而是根据锁的竞争情况产生的。这就会导致主从复制的方式SBR(statement-based replication)出现问题,因为主从之间的自增长值不一致会导致数据不一致的情况。因此,如果使用SBR进行主从复制,不建议将innodb_autoinc_lock_mode的值设置为2。而使用row-based replication(RBR)可以确保在主库上使用互斥量产生自增长值,并在从库上使用相同的方法生成相同的自增长值。这样就可以在保证并发性能的同时,保持主从复制之间数据的一致性。

使用mysql自增长的坏处:

  • 强依赖DB。不同数据库语法和实现不同,数据库迁移的时候、多数据库版本支持的时候、或分表分库的时候需要处理,会比较麻烦。当DB异常时整个系统不可用,属于致命问题。
  • 单点故障。在单个数据库或读写分离或一主多从的情况下,只有一个主库可以生成。有单点故障的风险。
  • 数据一致性问题。配置主从复制可以尽可能的增加可用性,但是数据一致性在特殊情况下难以保证。主从切换时的不一致可能会导致重复发号。
  • 难于扩展。在性能达不到要求的情况下,比较难于扩展。ID发号性能瓶颈限制在单台MySQL的读写性能。

🎉 3. 锁机制

为了保证自增长主键的唯一性,MySQL 会在插入新记录时对表进行加锁,防止其他同时进行的操作干扰。具体来说,MySQL 会在表级别上加一个排他锁,也就是 WRITE 锁。这会阻塞其他的写操作,直至当前操作完成。

🎉 4. 如何处理插入失败

如果在插入新记录时出现冲突,也就是主键值已经存在,MySQL 会返回一个错误。这时候,我们可以根据实际情况进行处理,例如重试或者更新已有记录等。

总之,使用自增长主键可以方便地实现记录的唯一标识,提高数据库查询效率和数据完整性。不过在使用过程中,需要注意锁机制和异常处理等问题。

🍊 索引失效、聚集索引、辅助索引、覆盖索引、联合索引

🎉 0.索引失效的几种情况?

  • 如果条件中有or,即使其中有部分条件带索引也不会使用。
  • 对于复合索引,如果不使用前列,后续列也将无法使用。
  • like以%开头。列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不使用索引。
  • where中索引列有运算,有函数的,不使用索引。
  • 如果mysql觉得全表扫描更快的时候,数据少的情况下,不使用索引。

🎉 1. 什么是聚集索引?

聚集索引定义了表中数据的物理顺序,并且每个表只能有一个聚集索引。聚集索引按照指定列的顺序来存储表中的数据。当对基于聚集索引的列进行查询时,数据库引擎能够很快地找到指定的数据。

InnoDB存储引擎的表是一种按主键顺序存放数据的表格。聚集索引是一种按照主键构建的B+树,其中叶子节点存储整张表的行记录数据。这些叶子节点被称为数据页,并通过双向链表相互连接。因为每张表只能有一个聚集索引,所以查询优化器常常会选择使用聚集索引,因为它可以在数据页上直接找到所需的数据,排序和范围查询速度非常快。如果需要查询某个范围内的数据,可以通过叶子节点的上层中间节点得到页的范围,之后直接读取数据页即可。比如,如果我们想查询一张注册用户的表中最新注册的10位用户,就可以通过简单的SQL查询语句 SELECT * FROM Profile ORDER BY id LIMIT 10; 轻松实现,而不需要额外的数据排序操作。

🎉 2. 什么是辅助索引?

辅助索引也称为非聚集索引,它建立在聚集索引或堆(没有聚集索引)的基础上。辅助索引的作用是提高查询的性能,辅助索引并不定义数据的物理顺序,而是通过指向数据的逻辑指针来访问数据的。

对于辅助索引(Secondary Index,也称非聚集索引),叶子节点并不包含行记录的全部数据。叶子节点除了包含键值以外,每个叶子节点中的索引行中还包含了一个书签(bookmark)。该书签用来告诉InnoDB存储引擎哪里可以找到与索引相对应的行数据。由于InnoDB存储引擎表是索引组织表,因此InnoDB存储引擎的辅助索引的书签就是相应行数据的聚集索引键。辅助索引的存在并不影响数据在聚集索引中的组织,因此每张表上可以有多个辅助索引。当通过辅助索引来寻找数据时,InnoDB存储引擎会遍历辅助索引并通过叶级别的指针获得指向主键索引的主键,然后再通过主键索引来找到一个完整的行记录。举例来说,如果在一棵高度为3的辅助索引树中查找数据,那需要对这棵辅助索引树遍历3次找到指定主键,如果聚集索引树的高度同样为3,那么还需要对聚集索引树进行3次查找,最终找到一个完整的行数据所在的页,因此一共需要6次逻辑IO访问以得到最终的一个数据页。

🎉 3. 什么是覆盖索引?

覆盖索引是一种特殊的辅助索引,它包含了查询所需要的所有列数据,因此无需再到聚集索引或堆中去查找数据。这样的索引查询效率非常高,可以大大提高查询性能。

🎉 4. 如何创建一个联合索引?

联合索引是基于多个列的组合来创建的,它可以使得查询的效率更高。创建联合索引的语法如下:

CREATE INDEX index_name ON table_name (column1, column2, ...)

其中,index_name 为索引的名称,table_name 为表的名称,column1、column2、… 为列名。需要注意的是,联合索引的列顺序非常重要,查询时必须按照索引列的顺序来查询才能发挥索引的作用。

🎉 5. 聚集索引与辅助索引的优缺点:

聚集索引的优点是能够快速查找某个指定的条目,因为它们能够让数据在磁盘上物理地按照顺序存储,可以提高查询效率。但是,聚集索引缺点是插入和更新数据变慢,因为需要重新排序数据。

辅助索引的优点是不会对插入和更新操作产生影响,因为它们并不参与数据物理顺序的排序,查询较快。缺点是因为需要通过逻辑指针找到数据,因此查询速度比聚集索引慢一些。

🎉 6. 什么情况下应该使用覆盖索引?

使用覆盖索引的情况是当查询只需要查询索引列时,可以使用覆盖索引来提高查询速度。因为覆盖索引包含了所有需要查询的列,而不需要再到聚集索引或堆中去查找数据。

🍊 SQL的执行流程

第一步,先连接到这个数据库上,这时候接待你的就是连接器。连接器负责跟客户端建立连接、获取权限、维持和管理连接。用户名密码认证通过,连接器会到权限表里面查出你拥有的权限。一个用户成功建立连接后,即使你用管理员账号对这个用户的权限做了修改,也不会影响已经存在连接的权限。修改完成后,只有再新建的连接才会使用新的权限设置。连接完成后,如果你没有后续的动作,这个连接就处于空闲状态,你可以在 show processlist 命令中看到它。客户端如果长时间不发送command到Server端,连接器就会自动将它断开。这个时间是由参数 wait_timeout 控制的,默认值是 8 小时。

第二步:查询缓存。MySQL 拿到一个查询请求后,会先到查询缓存看看,之前是不是执行过这条语句。之前执行过的语句及其结果可能会以 key-value对的形式,被直接缓存在内存中。key 是查询的语句,value 是查询的结果。如果你的查询能够直接在这个缓存中找到 key,那么这个value就会被直接返回给客户端。如果语句不在查询缓存中,就会继续后面的执行阶段。执行完成后,执行结果会被存入查询缓存中。你可以看到,如果查询命中缓存,MySQL不需要执行后面的复杂操作,就可以直接返回结果,这个效率会很高。大多数情况查询缓存就是个鸡肋,为什么呢?因为查询缓存往往弊大于利。查询缓存的失效非常频繁,只要有对一个表的更新,这个表上所有的查询缓存都会被清空。因此很可能你费劲地把结果存起来,还没使用呢,就被一个更新全清空了。对于更新压力大的数据库来说,查询缓存的命中率会非常低。这个鸡肋也有地方可以去使用它,比如说不会改变的表数据,极少更新的表,像一些系统配置表、字典表,全国的省份之类的表,这些表上的查询适合使用查询缓存。MySQL提供了这种“按需使用”的方式,可以将my.cnf参数query_cache_type 设置成2,query_cache_type有3个值:0代表关闭查询缓存,1代表开启,2代表当sql语句中有SQL_CACHE关键词时才缓存。确定要使用查询缓存的语句,用 SQL_CACHE显式指定,比如,select SQL_CACHE * from user where ID=5;

第三步,如果没有命中查询缓存,就要开始真正执行语句了。MySQL 需要知道你要做什么,需要对 SQL 语句做解析。

分析器先会做“词法分析”,你输入的一条 SQL 语句,MySQL需要识别出里面的字符串分别是什么,代表什么。MySQL从你输入的"select"这个关键字识别出来,这是一个查询语句。它也要把字符串“user”识别成“表名 user”,把字符串“ID”识别成“列 ID”。做完了这些识别以后,就要做“语法分析”。根据词法分析的结果,语法分析器会根据语法规则,判断你输入的这个 SQL语句是否满足MySQL语法。如果你的语句不对,就会收到“您的SQL语法有错误”的错误提醒。语句正确之后,会丢到分析机里面执行分析,语法分析由Bison生成,经过bison语法分析之后,会生成一个语法树。比如,你的操作是select还是insert,你需要对那些字段进行操作,作用在哪张表上面,条件是什么。

经过了分析器,MySQL就知道这些字符串代表什么,要做什么了。在开始执行之前,还要先经过优化器的处理。

第四步,优化器,在表里面有多个索引的时候,决定使用哪个索引;或者在一个语句有多表关联的时候,优化器可以决定各个表的连接顺序,同一条多表查询的sql,执行的方案会有多种,比如,select * from user1 join user2 on user1.id = user2.id where user1.name=liaozhiwei and user2.name=haoshuai;既可以先从表user1 里面取出 name=liaozhiwei的 ID 值,再根据 ID 值关联到表user2,再判断user2 里面 name的值是否等于liaozhiwei。也可以先从表user2 里面取出 name=haoshuai的 ID 值,再根据 ID 值关联到user1,再判断user1 里面 name 的值是否等于haoshuai。这两种执行方法的逻辑结果是一样的,但是执行的效率会有不同,而优化器的作用就是决定选择使用哪一个方案。执行方案就确定下来了,然后进入执行器阶段。

第五步,开始执行的时候,要先判断一下你对这个表有没有执行查询的权限,如果没有,就会返回没有权限的错误。如果有权限,就打开表继续执行。打开表的时候,执行器就会根据表的引擎定义,去使用这个引擎提供的接口。比如,我有一条sql:select * from user where id=10;执行器调用 InnoDB 引擎接口取这个表的第一行,判断 ID 值是不是10,如果不是则跳过, 调用引擎接口取“下一行”,重复相同的判断逻辑,直到取到这个表的最后一行,如果是将这行保存在结果集中。执行器将遍历过程中所有满足条件的行组成的记录集作为结果集返回给客户端。到这一步,这个语句就执行完成了。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
3天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
16 2
|
8天前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
13天前
|
存储 缓存 Oracle
Java I/O流面试之道
NIO的出现在于提高IO的速度,它相比传统的输入/输出流速度更快。NIO通过管道Channel和缓冲器Buffer来处理数据,可以把管道当成一个矿藏,缓冲器就是矿藏里的卡车。程序通过管道里的缓冲器进行数据交互,而不直接处理数据。程序要么从缓冲器获取数据,要么输入数据到缓冲器。
Java I/O流面试之道
|
9天前
|
SQL 安全 Java
安全问题已经成为软件开发中不可忽视的重要议题。对于使用Java语言开发的应用程序来说,安全性更是至关重要
在当今网络环境下,Java应用的安全性至关重要。本文深入探讨了Java安全编程的最佳实践,包括代码审查、输入验证、输出编码、访问控制和加密技术等,帮助开发者构建安全可靠的应用。通过掌握相关技术和工具,开发者可以有效防范安全威胁,确保应用的安全性。
22 4
|
10天前
|
存储 缓存 Java
大厂面试必看!Java基本数据类型和包装类的那些坑
本文介绍了Java中的基本数据类型和包装类,包括整数类型、浮点数类型、字符类型和布尔类型。详细讲解了每种类型的特性和应用场景,并探讨了包装类的引入原因、装箱与拆箱机制以及缓存机制。最后总结了面试中常见的相关考点,帮助读者更好地理解和应对面试中的问题。
33 4
|
10天前
|
缓存 监控 Java
如何运用JAVA开发API接口?
本文详细介绍了如何使用Java开发API接口,涵盖创建、实现、测试和部署接口的关键步骤。同时,讨论了接口的安全性设计和设计原则,帮助开发者构建高效、安全、易于维护的API接口。
33 4
|
10天前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
50 4
|
21天前
|
开发框架 JavaScript 前端开发
HarmonyOS UI开发:掌握ArkUI(包括Java UI和JS UI)进行界面开发
【10月更文挑战第22天】随着科技发展,操作系统呈现多元化趋势。华为推出的HarmonyOS以其全场景、多设备特性备受关注。本文介绍HarmonyOS的UI开发框架ArkUI,探讨Java UI和JS UI两种开发方式。Java UI适合复杂界面开发,性能较高;JS UI适合快速开发简单界面,跨平台性好。掌握ArkUI可高效打造符合用户需求的界面。
72 8
|
16天前
|
SQL Java 程序员
倍增 Java 程序员的开发效率
应用计算困境:Java 作为主流开发语言,在数据处理方面存在复杂度高的问题,而 SQL 虽然简洁但受限于数据库架构。SPL(Structured Process Language)是一种纯 Java 开发的数据处理语言,结合了 Java 的架构灵活性和 SQL 的简洁性。SPL 提供简洁的语法、完善的计算能力、高效的 IDE、大数据支持、与 Java 应用无缝集成以及开放性和热切换特性,能够大幅提升开发效率和性能。
|
16天前
|
存储 Java 关系型数据库
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践,包括连接创建、分配、复用和释放等操作,并通过电商应用实例展示了如何选择合适的连接池库(如HikariCP)和配置参数,实现高效、稳定的数据库连接管理。
34 2