Java面经

1.队列是否一直存在?下一次定时任务是否要重新创建队列?

答:队列是否一直存在取决于队列是不是持久化的队列,如果是的话则一直存在不是的话就不是一直存在,比如说像rbmq,rocketmq这些中间件就是持久化存在的,启动时创建一次,然后就一直存在

java 复制代码
@Configuration
public class RabbitMqConfig {
    @Bean
    public Queue myTaskQueue() {
        // durable=true:持久化队列,Broker重启后仍存在
        return QueueBuilder.durable("task.queue").build();
    }
}

像定时任务内部的内存队列(如 ThreadPoolExecutor),@Async的异步线程池,它们都是属于jvm层面的,每次启动会创建,每次关闭会销毁。

即;

  • RabbitMQ 这类持久化中间件队列:创建后永久存在(除非手动删),仅首次启动创建一次,后续无需重建
  • JVM 内存队列(@Async / 定时任务线程池队列):项目关闭即销毁,每次项目启动都会重新创建(但启动后只创建一次,运行期间复用,不是每次执行任务都创建)
2.消费者的并发线程数是多少?

消费者并发线程数没有固定值,核心取决于业务场景、硬件资源、消息生产速度、消费逻辑耗时

  • 理论参考值:线程数 = CPU核心数 * (1 + 等待时间/计算时间)(阿姆达尔定律)。比如消费逻辑以 IO 等待(查 DB、调用接口)为主,等待时间远大于计算时间,线程数可设为 CPU 核心数的 2~4 倍;如果是纯内存计算,线程数接近 CPU 核心数即可。
  • 项目实操:比如基于 RocketMQ 的订单消费场景,服务器是 8 核 16G,消费逻辑需要调用支付接口(IO 密集),最终设置并发线程数为 16~24,同时配合流控、重试机制,避免线程过多导致上下文切换频繁或数据库连接池耗尽。
3.JVM 内存调优(堆大小、新生代 / 老年代分配)

调优前必须先通过工具(JVisualVM、Arthas、Prometheus+Grafana)分析GC 日志、内存快照(heap dump),明确问题(如频繁 Full GC、OOM、Young GC 耗时过长),而非盲目调参。

  • 观察 Young GC 频率:从原来的 1 分钟 / 次优化为 5 分钟 / 次,单次耗时从 200ms 降至 50ms 以内;
  • Full GC 频率:从原来的 1 小时 / 次降至 24 小时 / 次(仅凌晨低峰期出现);
  • 接口响应时间:P99 从 500ms 降至 150ms 以内。
4.对 MySQL 索引的了解及项目中的使用场景?

索引本质:MySQL 索引是帮助引擎快速获取数据的数据结构(B + 树为主),核心作用是减少磁盘 IO,提升查询效率。

核心类型:聚簇索引(主键索引)、二级索引(普通索引、唯一索引、联合索引)、全文索引等

索引一般有:B+树,hash索引,倒排索引,R树索引。

索引从存储方式又分为:聚簇索引和非聚簇索引。

聚簇索引: 聚簇索引是基于主键构建的索引(主键索引)

非聚簇索引: 非主键的那些字段(也是索引)

  • 一张表有很多棵 B+ 树

    • 1 棵 聚簇索引树(主键)
    • 每建一个普通索引,就多 1 棵 非聚簇索引树
  • **非聚簇索引树里存什么?**只存:

    • 索引字段的值
    • 主键 id不存其他数据。
  • 查询流程

    1. 先走 非聚簇索引树
    2. 找到对应的 主键 id
    3. 拿着 id 去 聚簇索引树
    4. 聚簇索引的 叶子节点存整行数据
  • 所有真实数据,只存在聚簇索引里

5.订单号长度不等时,索引如何处理?

订单号长度不等(比如有的是 16 位、有的是 20 位),只要订单号字段是字符串类型(VARCHAR/CHAR),创建索引依然生效,但需要注意:

  • 建议使用VARCHAR而非CHAR:CHAR 是定长,长度不等时会浪费存储空间;VARCHAR 是变长,仅存储实际长度 + 1 字节(长度标识);
  • 避免前缀截断:如果订单号长度差异大,不要盲目用前缀索引(如KEY idx_order_sn (order_sn(10))),除非能保证前缀的唯一性,否则会导致索引失效或回表次数增加;
  • 项目实操:订单表order_sn字段定义为VARCHAR(64),直接创建唯一索引UNIQUE KEY idx_order_sn (order_sn),即使长度不等,查询WHERE order_sn = 'xxx'依然能走索引,且效率不受影响。
6.可变字符串作为索引是否生效?会有什么问题?

订单号长度不等(比如有的是 16 位、有的是 20 位),只要订单号字段是字符串类型(VARCHAR/CHAR),创建索引依然生效,但需要注意:

  • 建议使用VARCHAR而非CHAR:CHAR 是定长,长度不等时会浪费存储空间;VARCHAR 是变长,仅存储实际长度 + 1 字节(长度标识);
  • 避免前缀截断:如果订单号长度差异大,不要盲目用前缀索引(如KEY idx_order_sn (order_sn(10))),除非能保证前缀的唯一性,否则会导致索引失效或回表次数增加;
  • 项目实操:订单表order_sn字段定义为VARCHAR(64),直接创建唯一索引UNIQUE KEY idx_order_sn (order_sn),即使长度不等,查询WHERE order_sn = 'xxx'依然能走索引,且效率不受影响。
7.联合索引的顺序与查询效率是否相关?

高度相关,核心遵循 "最左匹配原则":

  • 联合索引的顺序决定了查询是否能命中索引,以及索引的筛选效率;
  • 设计原则:区分度高的字段放前面(区分度 = 不同值的数量 / 总记录数)。
  • 示例:项目中订单表的联合索引idx_user_time (user_id, create_time)
    • 命中索引:WHERE user_id = 100 AND create_time > '2026-01-01'(全匹配)、WHERE user_id = 100(左前缀匹配);
    • 不命中索引:WHERE create_time > '2026-01-01'(跳过左前缀);
    • 效率差异:如果把区分度低的create_time放前面,索引筛选性差,比如WHERE create_time > '2026-01-01' AND user_id = 100,即使能通过优化器调整顺序,但索引树的结构依然低效,查询时需要扫描更多索引节点。
8.聚簇索引能否手动单独建立多个?

不能

  • 聚簇索引的核心特点:InnoDB 引擎中,聚簇索引的叶子节点直接存储整行数据,且一张表只能有一个聚簇索引
  • 默认规则:InnoDB 会优先以主键 作为聚簇索引;如果没有主键,会选择第一个唯一非空索引;如果都没有,会隐式创建一个 6 字节的row_id作为聚簇索引;
  • 注意:无法手动创建多个聚簇索引,因为这会导致数据存储结构混乱(整行数据无法同时存储在多个 B + 树的叶子节点),如果需要多维度查询,应创建二级索引(普通 / 联合索引),而非试图创建多个聚簇索引
相关推荐
小羊没烦恼!2 天前
微服务化的基石——持续集成
java·大数据·word·powerpoint·.net
俊昭喜喜里2 天前
java中的继承和多态的区别
java
小羊没烦恼!2 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
譕痕2 天前
JSONObject与JSONArray封装数据格式区别
java·json
胡写代码2 天前
别再前后端各写一套表单校验了
java·后端
小鱼能吃糖2 天前
缺陷修复总览 · mall电商项目:5类缺陷,1个病根,4个业务域
java·电商
此时不提桶,更待何时2 天前
01-06-A-JVM排查实战详解
java·jvm
伞伞悦读2 天前
【第38期】Python 模块与包详解:import、from、模块搜索路径、包结构和 __init__
开发语言·python
vipxieliang2 天前
ValidX 在 DDD 领域驱动设计中的实践
java·spring boot
C语言小火车2 天前
C/C++ 为什么需要编译器?
开发语言·c++