原创

Java面试题p8

温馨提示:
本文最后更新于 2025年05月08日,已超过 401 天没有更新。若文章内的图片失效(无法正常加载),请留言反馈或直接联系我

MySQL常用的引擎

InnoDB:mysql5.1后的默认数据库引擎,提供对数据库ACID事务的支持,并且提供行级锁和外键的约束。设计目的是处理大数据容量的数据库系统。MySQL运行时,InnoDB会在内存中建立缓冲池,用于缓冲数据和索引

该引擎不支持全文搜索,同时启动较慢。它是不保存表的行数,所以 select count(*) from table;指令时,需要扫描全表。锁的粒度小,写操作不会锁定全表。并发较高场景能提升效率

MyIASM引擎不提供事务支持。不支持行级锁和外键。因此当执行插入和更新语句时,即执行写操作的时候需要定这个,会导致效率降低。

MyISAM引擎保存了表的行数,当执行 select count(*) from table 语句时,可直接取保存的,不用扫描全表。适合读操作远多于写操作,且不需要事务支持的场景

MySQL的表锁和行锁

MyISAM:仅支持表锁。InnoDB:支持表锁和行锁,默认行锁

表级锁:开销小,加锁快,不会出现死锁。锁定粒度大,发生锁冲突概率最高,并发量最低

行级锁:开销大,加锁慢,会出现死锁。锁粒度小,发生锁冲突概率小,并发度最高

悲观锁和乐观锁

乐观锁:每次去拿数据的时候都认为别人不会修改,所以不会上锁。但是在提交更新的时候回判断一下在此期间别人有没有去更新这个数据

悲观锁:每次去拿数据 都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻止,直到这个锁被释放。

乐观锁自己实现。在表里添加一个version字段,每次修改成功值加1,这样每次修改的时候先对比一下,自己拥有的version和数据库现在的version是否一致,如果不一致就不修改,这样就实现了乐观锁

MySQL问题排查

使用 show processlist 命令查看当前所有的连接信息

使用 explain 命令查询 SQL语句 执行计划

开启慢查询日志,查看慢查询的SQL

MySQL性能优化

  • 为搜索字段创建索引
  • 避免使用 select * ,列出需要查询的字段
  • 垂直分割分表
  • 选择正确的存储引擎

Redis使用场景

Redis是C语言开发高速缓存数据库

使用场景:

  1. 记录帖子点赞数、点击数、评论数
  2. 缓存近期热帖
  3. 缓存文章详情信息
  4. 记录用户会话信息

Redis功能

数据缓存功能

分布式锁的功能

支持数据持久化

支持事务

支持消息队列

Redis单线程

因为cpu不是Redis的瓶颈,Redis的瓶颈可能是机器内存或是网络带宽。既然单线程容易实现,而且cpu不会是瓶颈,就使用单线程

Redis的性能,几十万/s

缓存穿透

查询一个一定不存在的数据,由于缓存不命中时需要从数据库查询,查不到则不写入缓存,这将导致整个不存在的数据每次请求都要到数据库去查询,造成缓存穿透

解决方案:最简单粗暴的方法,如果一个查询返回的数据为空(不管数据不存在,还是系统故障),直接将这个空结果进行缓存,但它的过期时间会很短,最长不超过5分钟

Redis支持的数据类型

String(字符串)

list(列表)

hash散列表

set(集合)

zset(有序集合)

Redis支持的Java客户端

Reddisson、jedis、lettuce

保持缓存和数据库一致性

合理设置缓存的过期时间

新增、更改、删除数据库操作时,同步更新Redis,可以使用事务机制保证数据的一致性

Redis的持久化方式

RDF(Redis Database):指定的时间间隔,对你的数据进行快照存储

AOF(Append Only File):每一个收到的写命令都通过write函数追加到文件中

Redis内存优化

尽量使用Redis的散列表,把相关的信息放到散列表里面存储,而不是每个字段单独存储,可以有效减少内存的使用。如:将web系统的用户对象,应该放到散列表里面再整体存储到Redis,而不是把用户的姓名、年龄、密码等字段分别设置key存储

Redis淘汰策略

volatile-Iru:从已设置过期时间的数据集(sever.db[i].expires)中挑选最近最少使用的数据淘汰

volatile-ttl:从已设置过期时间的数据集(sever.db[i].expires)中,根据过期时间的先后进行淘汰

volatile-random:从已设置过期时间的数据集(sever.db[i].expires)中任意选择数据淘汰

allkeys-Iru:从(所有)数据集(sever.db[i].dict)中挑选最近最少使用的数据淘汰

allkeys-random:从(所有)数据集(sever.db[i].dict)中任意选择数据淘汰

noenviction(驱逐):不进行数据淘汰(缓存写满,再有写请求,直接返回错误

JVM主要组成部分及作用

类加载器(classLoader)

运行时数据区(Runtime Data Area)

执行引擎(Execution Engine)

本地库接口(Native Inteface)

运行流程

首先通过 类加载器(classLoader)会把Java代码转换成字节码,

运行时数据区(Runtime Data Area) 再把字节码加载到内存中,而字节码文件只是JVM的一套指令集规范,并不能直接交给底层操作系统执行,因此,

执行引擎(Execution Engine) 将字节码翻译成磁层系统指令,再交由cpu执行。

而这个过程中需要调用其他语言的 本地库接口(Native Inteface)来实现整个程序的功能

堆栈区别 

功能:

堆:用来存放对象

栈:用来执行程序

共享性:

堆:是线程共享的

栈:私有的

空间大小:堆大小远大于栈

队列和栈

队列和栈都是用来预存储数据

队列允许先进先出检索元素(例外:Deque允许接口从两端检索数据)

和队列相似,对元素后进先出进行检索

类装载的执行过程

加载:根据查找路径,找到相应的class文件然后导入

检查:检查加载的class文件的正确性

准备:给类中的静态变量分配内存空间

解析:虚拟机将常量池中的符号引用替换成直接引用的过程。

符号引用就理解为一个标示,直接引用-->直接指向内存中的地址

初始化:对静态变量和静态代码块执行初始化工作

正文到此结束