25年10月智晟未来信息科技 Java开发实习生 二面

#JAVA##JAVA面经##JAVA内推#

1. 分享一个你印象最深的 Bug 吧~当时现象是啥?怎么一步步定位到根因的?最后怎么解决的?从中学到了啥?

回答:

现象:电商项目中,用户支付完成后偶发出现“订单状态已支付,但库存未扣减”的情况,且仅在高峰期(每秒超200笔支付)出现,低峰期完全正常。 定位过程

  1. 先查日志:支付回调接口日志显示“扣减库存成功”,但库存表数据未变,排除接口未执行的问题;
  2. 查数据库事务:支付流程是“扣库存→改订单状态→记录流水”,事务配置为默认的REPEATABLE READ,但发现扣库存的SQL用了UPDATE 库存表 SET 数量=数量-1 WHERE 商品ID=?,未加行锁范围限制;
  3. 查数据库锁等待:通过show engine innodb status发现高峰期存在大量行锁等待,部分事务因锁超时(innodb_lock_wait_timeout默认5秒)回滚,但订单状态更新因提前提交(代码逻辑错误,拆分了事务)未回滚;
  4. 根因定位:代码中将“扣库存”和“改订单状态”拆分为两个独立事务,高峰期扣库存事务因锁等待超时回滚,但改订单状态事务已提交,导致数据不一致。

解决方式

  1. 合并事务:将“扣库存→改订单状态→记录流水”纳入同一个数据库事务,保证原子性;
  2. 优化锁机制:扣库存SQL改为UPDATE 库存表 SET 数量=数量-1 WHERE 商品ID=? AND 数量>=1,并添加行锁提示FOR UPDATE
  3. 调整锁超时:将innodb_lock_wait_timeout调整为10秒,同时添加重试机制(最多3次)。

学到的经验

  1. 事务必须保证原子性,核心业务流程不能拆分事务;
  2. 高峰期的并发问题无法通过“表面排查”发现,需结合数据库锁、事务日志分析;
  3. 并发场景下,更新操作必须加“行锁范围限制”,避免全表锁或无效更新。

2. 多表联合查询(比如 LEFT JOIN)变慢了,你一般会从哪些地方入手排查和优化?有实际处理过的例子吗?

回答:

排查方向

  1. 索引层面
    • 检查关联字段(JOIN ON 后的字段)是否加索引,LEFT JOIN 中左表关联字段必须加索引,右表关联字段建议加索引;
    • 检查查询字段是否包含“回表字段”(非索引字段),是否可通过覆盖索引减少回表;
  2. SQL 层面
    • 检查是否有不必要的 JOIN 表(比如关联了不需要的表);
    • 检查 WHERE 条件是否过滤了大量数据,是否将过滤条件前置(先过滤再 JOIN);
    • 检查是否使用了 SELECT *,是否只查询需要的字段;
  3. 数据库层面
    • 执行EXPLAIN分析执行计划,看是否出现“全表扫描(type=ALL)”“临时表(Using temporary)”“文件排序(Using filesort)”;
    • 检查表数据量,是否有大表(千万级以上)未分库分表;
  4. 数据层面
    • 检查是否有大量 NULL 值(LEFT JOIN 右表NULL值多会增加计算量);
    • 检查表碎片,是否需要OPTIMIZE TABLE整理碎片。

实际案例: 某物流项目中,LEFT JOIN查询“订单表(order)+ 物流表(logistics)+ 用户表(user)”时,响应时间从50ms涨到3s。

  • 排查:执行EXPLAIN发现物流表的关联字段order_id无索引,且查询字段包含logistics表的非索引字段(物流详情),出现全表扫描;
  • 优化:
    1. logistics.order_id添加普通索引;
    2. 将查询字段改为仅需的order.id, logistics.status, user.name,并创建覆盖索引idx_order_id_status (order_id, status)
    3. 将 WHERE 条件logistics.create_time > '2025-01-01'前置到子查询,先过滤物流表数据再 JOIN:
      SELECT o.id, l.status, u.name 
      FROM `order` o
      LEFT JOIN (SELECT order_id, status FROM logistics WHERE create_time > '2025-01-01') l ON o.id = l.order_id
      LEFT JOIN `user` u ON o.user_id = u.id
      WHERE o.status = 1;
      
  • 效果:响应时间降至80ms以内。

3. Redis 哨兵和 Cluster 集群,你觉得它们核心区别在哪?平时项目里怎么选?(比如数据量大小、高可用要求)

回答:

维度 Redis 哨兵(Sentinel) Redis Cluster(集群)
核心定位 主从高可用(故障自动切换) 分布式存储+高可用(分片+故障切换)
数据分片 无,所有节点数据全量复制(主从同步) 有,按槽位(16384个)分片,每个节点存部分数据
节点角色 主节点+从节点+哨兵节点(监控/决策) 主节点+从节点(无专门哨兵,自身实现故障检测)
扩容能力 弱(全量数据,扩容仅提升读性能) 强(分片扩容,可线性提升存储和性能)
故障切换 哨兵集群投票决定主节点切换 集群节点投票,自动将从节点提升为主节点
适用数据量 中小数据量(单节点能承载,如GB级) 大数据量(TB级,需分片存储)

选型策略

  1. 选哨兵的场景
    • 数据量小(单Redis节点可承载,如≤10GB);
    • 核心诉求是“高可用”(避免主节点宕机导致服务不可用);
    • 业务逻辑简单,无需分片,比如缓存热点数据、计数器、会话存储。 例:某后台管理系统,缓存用户权限数据(总量≤5GB),用哨兵保证主从切换,满足99.9%可用即可。
  2. 选Cluster的场景
    • 数据量大(单节点无法承载,如≥50GB);
    • 高并发读写(如每秒万级请求),需要分片分摊压力;
    • 核心诉求是“分布式存储+高可用”,比如电商商品缓存、订单缓存、秒杀库存。 例:某电商平台,商品缓存总量超100GB,QPS峰值5万,用Cluster分片为6个主节点+6个从节点,既满足存储需求,又保证高可用。

4. 小实操:怎么用 Linux 命令找出当前目录下所有 .log 文件里包含 "error" 的行,并存到 error_log.txt?(说说你会用哪些命令组合)

回答:

核心命令组合:grep(匹配关键词)+ find(查找文件),推荐两种常用方式:

方式1:基础版(适合新手,逻辑清晰)

# 1. find 查找当前目录下所有 .log 文件
# 2. xargs 传递文件列表给 grep
# 3. grep 匹配包含 "error" 的行(忽略大小写用 -i,显示行号用 -n)
# 4. > 重定向到 error_log.txt(覆盖写入),>> 是追加写入
find ./ -name "*.log" | xargs grep "error" > error_log.txt

方式2:进阶版(更健壮,处理特殊文件名如含空格)

# -print0 和 -0 配合,处理文件名含空格/特殊字符的情况
# -i:忽略大小写(可选,根据需求)
# -n:显示行号(可选,便于定位)
find ./ -name "*.log" -type f -print0 | xargs -0 grep -in "error" > error_log.txt

参数说明

  • ./:当前目录(可替换为绝对路径,如 /var/log/);
  • -name "*.log":匹配后缀为 .log 的文件;
  • -type f:仅匹配文件(排除目录);
  • -print0/-0:解决文件名含空格、换行等特殊字符的问题;
  • -i:忽略大小写(比如匹配 Error/ERROR/error);
  • -n:显示匹配行的行号(便于排查问题);
  • >:覆盖写入 error_log.txt,若需追加用 >>

验证:执行后可通过 cat error_log.txt 查看结果,确认是否包含所有含“error”的行。

5. 项目里遇到过数据库并发导致的数据不一致吗?怎么解决的?如果没遇到过,你觉得可以用哪些方案预防?(比如加锁、事务隔离级别)

回答:

实际案例: 某秒杀项目中,并发抢购同一商品时,出现“超卖”(库存为负数),核心原因是高并发下多个请求同时读取到“库存>0”,并执行扣减操作,导致数据不一致。

解决方式

  1. 数据库层面
    • 事务隔离级别调整:将默认的REPEATABLE READ改为READ COMMITTED,减少幻读;
    • 悲观锁:扣库存时用SELECT ... FOR UPDATE加行锁,保证同一时间只有一个请求能修改库存:
      BEGIN;
      -- 加行锁,锁定该商品的库存行
      SELECT stock FROM product WHERE id = 1 FOR UPDATE;
      -- 扣减库存(需判断库存>0)
      UPDATE product SET stock = stock - 1 WHERE id = 1 AND stock > 0;
      -- 检查影响行数,若为0则回滚
      IF ROW_COUNT() = 0 THEN ROLLBACK; ELSE COMMIT; END IF;
      
  2. 应用层面
    • 乐观锁:基于版本号或库存字段实现,避免长事务锁:
      UPDATE product SET stock = stock - 1 WHERE id = 1 AND stock = #{currentStock};
      
      (若更新失败,应用层重试3次,仍失败则提示“库存不足”);
    • 分布式锁:用Redis的SETNX实现分布式锁,保证同一商品只有一个请求进入扣库存逻辑。

预防方案(未遇到时)

  1. 锁机制
    • 悲观锁:适合写多读少、数据一致性要求极高的场景(如金融交易);
    • 乐观锁:适合读多写少、并发高的场景(如电商秒杀);
    • 分布式锁:跨服务/跨数据库的并发场景。
  2. 事务优化
    • 缩短事务时长(避免长事务占用锁);
    • 合理设置事务隔离级别(如READ COMMITTED避免不必要的锁等待)。
  3. 业务层面
    • 限流:对高并发接口做限流(如每秒最多1000请求),避免数据库压垮;
    • 预扣库存:提前将库存缓存到Redis,先扣Redis库存,再异步同步到数据库。

6. 前端要渲染大量数据时页面卡顿,你会从前端和后端分别怎么优化?(比如分页、虚拟滚动、懒加载)

回答:

前端优化(核心:减少DOM渲染量、降低重绘重排):

  1. 虚拟滚动(核心方案)
    • 原理:只渲染可视区域内的DOM节点,滚动时动态替换内容,比如10万条数据仅渲染20条可视节点;
    • 实现:用成熟组件(如Vue的vue-virtual-scroller、React的react-window),避免手写复杂逻辑。
  2. 分页加载
    • 基础分页:按页码/条数加载(如每页20条),配合“下一页”“上一页”;
    • 无限滚动:滚动到底部自动加载下一页(结合节流函数,避免频繁请求)。
  3. 懒加载
    • 非核心数据(如列表项的详情、图片)延迟加载,仅当用户点击/滚动到该位置时加载;
    • 图片懒加载:用loading="lazy"或自定义指令,先加载占位图。
  4. 渲染优化
    • 减少DOM嵌套,避免复杂样式(如position: fixed);
    • requestAnimationFrame处理数据渲染,避免同步渲染阻塞主线程;
    • 大数据计算(如排序、过滤)放到Web Worker,不占用主线程。

后端优化(核心:减少数据传输量、提升接口响应速度):

  1. 数据分页查询
    • LIMIT offset, size(MySQL)或ROWNUM(Oracle)实现分页,避免全表查询;
    • 优化分页SQL:加索引,避免SELECT *,只返回前端需要的字段。
  2. 数据预处理
    • 后端提前过滤、排序、聚合数据(如统计总数、计算百分比),避免前端处理大量数据;
    • 缓存分页结果:用Redis缓存热门分页数据(如前10页),减少数据库查询。
  3. 接口优化
    • 压缩数据:开启Gzip压缩,减少传输体积;
    • 批量接口合并:将多个小接口合并为一个,减少HTTP请求数;
    • 异步返回:若数据处理耗时,返回“任务ID”,前端轮询获取结果(避免长连接阻塞)。

案例:某后台系统渲染10万条订单数据,前端卡顿严重。

  • 前端:用vue-virtual-scroller实现虚拟滚动,仅渲染可视区域(约30条);
  • 后端:分页查询(每页50条),并缓存前20页数据,接口响应时间从2s降至100ms;
  • 效果:页面流畅无卡顿,滚动时无明显延迟。

7. 数据库

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

本专栏在精不在多,内容分为八股文、大厂真实面经,面试通过后将offer和面试题私发给我,可退还专栏的收益部分费用。欢迎大家共建专栏

全部评论

相关推荐

昨天 16:08
武汉大学 Java
面试时间:2026-3-10面试部门:QQ后台(QQ空间?)面试时间:14:30-15:30面试方式:  面呗上来手撕:非Hot100,十进制大数字符串转二进制字符串(取模求余算法)面试(有点不对口,该部门主要用C++/Go)做非web后端个人感觉挺难的,主要是问的都不是准备的哎哎一、基础操作系统:1.操作系统内存分配2.32位机器和64位机器区别(???)3.为什么需要分页,为什么需要分段(???)4.虚拟页表了解吗,干什么的?5.32位机器最大内存(???)计算机网络(悲)1.滑动窗口算法了解吗2.流量控制3.拥塞控制是什么,区别于流量控制4.滑动窗口什么时候更改尺寸(???)二、进入项目(也没咋问具体业务)1.Linux用过吧,常用命令2.Redis自己怎么用(答本地Redis+RedisInsight管理,port:6379)3.Redis集群用过吗(没)4.好我们来聊Redis集群(主从,哨兵,集群)项目怎么选?(???)5.AP架构讲一讲(难啊)6.RAG流程。7.RAG分片怎么做?如何优化8.RAG检索怎么优化,多路召回讲一讲9.RAG的幻觉怎么降低的三、其他问题1、第一次实习?(解释了原因)2.如何保证到岗,base深圳3.平时用什么大模型,不同的效果分析4、反问个人感觉有点非常规,准备的没咋问,冷门408问题有点好久没看了。。。问了面试官业务负责,和对自己评价,面试官建议多看基础。。。5分钟后官网过,等二面邮件中。
查看22道真题和解析
点赞 评论 收藏
分享
评论
1
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务