头图

先来唠唠

最近成都春招现场搞了个大新闻——直接用AI当面试官

网上有个人分享自己的经历:他全程对着电脑摄像头答题,AI不光听他说话,还盯着他的表情打分;他还说自己刚开口自我介绍,网突然卡了3秒,结果系统直接弹了个‘抗压能力不足’的评价,气得他差点摔手机。

但这事儿也有魔幻的另一面:有人靠着AI给的‘面试建议’(比如说话别太快、多笑一笑),还真拿到了大厂offer;招聘会数据说,AI筛人比HR快3倍,一上午面了上千人

问题是,这玩意儿到底靠不靠谱?有人觉得公平,毕竟AI不看学历只看表现;也有人吐槽‘面完都不知道输哪儿’。如果是你,愿意让一个算法决定你的工作机会吗?评论区聊聊


面经分享

今天分享的面经是万兴的一面,挺简单的,看一下你都会不会:

一、介绍一下 Git 的使用

Git 是一个分布式版本控制系统,用于跟踪代码变更和协作开发。以下是核心使用场景:

  1. 基础操作

    • git init:初始化本地仓库。
    • git add <file>:将文件添加到暂存区(git add . 添加所有文件)。
    • git commit -m "message":提交更改到本地仓库。
    • git status:查看当前仓库状态(如未跟踪/已修改的文件)。
  2. 分支管理

    • git branch:查看分支列表。
    • git checkout -b <branch>:创建并切换到新分支。
    • git merge <branch>:合并指定分支到当前分支。
    • git rebase <branch>:变基操作(整理提交历史)。
  3. 远程仓库

    • git clone <url>:克隆远程仓库到本地。
    • git pull:拉取远程分支并合并到本地。
    • git push:推送本地提交到远程仓库。
  4. 撤销与回退

    • git reset --hard <commit_id>:回退到指定提交(慎用)。
    • git revert <commit_id>:生成新提交以撤销某次更改。

二、JWT

JWT(JSON Web Token) 是一种用于身份验证的开放标准(RFC 7519),结构为 Header.Payload.Signature

  1. Header

    • 声明令牌类型(如 JWT)和签名算法(如 HS256)。
  2. Payload

    • 包含用户信息(如用户 ID、角色)和其他声明(如过期时间 exp)。
  3. Signature

    • 对前两部分签名,防止篡改(例如:HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret))。

用途

  • 用户登录后,服务端生成 JWT 返回给客户端,客户端后续请求携带 JWT 进行身份验证。

优点

  • 无状态,适合分布式系统。
  • 支持自定义数据,减少数据库查询。

缺点

  • 令牌一旦签发,在有效期内无法主动失效。

三、缓存穿透、击穿、雪崩

1. 缓存穿透

概念:查询数据库中不存在的数据,导致请求直接穿透到数据库。
解决

  • 布隆过滤器:拦截无效请求。
  • 缓存空值:对不存在的数据缓存空值并设置短过期时间。
2. 缓存击穿

概念:热点 Key 突然失效,大量请求直接打到数据库。
解决

  • 互斥锁:仅允许一个线程重建缓存。
  • 永不过期:逻辑过期时间配合异步更新。
3. 缓存雪崩

概念:大量 Key 同时过期或缓存服务宕机,导致数据库压力激增。
解决

  • 随机过期时间:避免集中失效。
  • 集群部署:如 Redis Cluster 保障高可用。

四、慢查询

概念:执行时间超过阈值的 SQL 查询(如 MySQL 默认阈值为 10 秒)。
排查与优化

  1. 开启慢查询日志

    SET GLOBAL slow_query_log = ON;  
    SET GLOBAL long_query_time = 2; -- 设置阈值  
  2. 分析工具

    • EXPLAIN:查看执行计划。
    • mysqldumpslow:分析日志。
  3. 优化手段

    • 添加索引。
    • 优化 SQL 结构(如避免 SELECT *)。

五、数据库锁都有哪些

  1. 行锁:锁定单行(如 InnoDB 的 SELECT ... FOR UPDATE)。
  2. 表锁:锁定整张表(如 MyISAM 的写锁)。
  3. 共享锁(S 锁):允许其他事务读,禁止写。
  4. 排他锁(X 锁):禁止其他事务读写。
  5. 意向锁:快速判断表级冲突(如意向共享锁 IS)。
  6. 间隙锁:锁定范围(防止幻读)。

六、不同隔离层级不同在哪里

  1. 读未提交(Read Uncommitted):可能读到未提交的数据(脏读)。
  2. 读已提交(Read Committed):只能读到已提交的数据(解决脏读)。
  3. 可重复读(Repeatable Read):事务内多次读取结果一致(解决不可重复读)。
  4. 串行化(Serializable):完全隔离(解决幻读,但性能低)。

七、MVCC

多版本并发控制(Multi-Version Concurrency Control) 通过版本链实现非锁定读:

  1. 版本链:每行数据关联多个版本(通过 DB_TRX_IDDB_ROLL_PTR)。
  2. ReadView:事务启动时生成快照,决定可见哪个版本。

    • 读已提交:每次查询生成新 ReadView。
    • 可重复读:事务内复用同一个 ReadView。

八、Redis 数据结构

  1. String:字符串、整数、二进制数据。
  2. List:双向链表(支持队列、栈)。
  3. Hash:键值对集合。
  4. Set:无序唯一集合。
  5. Zset:有序集合(基于跳跃表 + 字典)。
  6. 其他:Bitmaps、HyperLogLog、Streams。

九、Zset 的底层原理

Zset 通过 跳跃表(Skip List)哈希表(Hash Table) 实现:

  1. 跳跃表:支持 O(logN) 复杂度的范围查询(如 ZRANGE)。
  2. 哈希表:存储成员到分值的映射,实现 O(1) 的单点查询。
    特点
  3. 数据按分值排序,成员唯一。
  4. 插入、删除、查询的时间复杂度均为 O(logN)。

十、Go 中的 GMP 模型

GMP 是 Go 的并发调度模型:

  1. G(Goroutine):轻量级用户态线程。
  2. M(Machine):操作系统线程,由内核调度。
  3. P(Processor):逻辑处理器,管理本地队列和上下文。

调度逻辑

  • P 的数量:默认等于 CPU 核心数(通过 GOMAXPROCS 设置)。
  • 工作窃取:当 P 的本地队列为空时,从其他 P 的队列窃取 G。
  • 系统调用:若 G 发生阻塞系统调用,M 会解绑 P 并创建新 M 继续执行。

快速排序

package main  

import "fmt"  

func quickSort(arr []int) []int {  
    if len(arr) <= 1 {  
        return arr  
    }  
    pivot := arr[len(arr)/2]    // 选择中间元素作为基准  
    left, right := []int{}, []int{}  
    for _, num := range arr {  
        if num < pivot {  
            left = append(left, num)  
        } else if num > pivot {  
            right = append(right, num)  
        }  
    }  
    // 递归排序左右部分,合并结果  
    return append(append(quickSort(left), pivot), quickSort(right)...)  
}  

func main() {  
    arr := []int{3, 6, 8, 10, 1, 2, 1}  
    fmt.Println(quickSort(arr)) // 输出 [1 1 2 3 6 8 10]  
}  

说明

  • 时间复杂度:平均 O(n log n),最差 O(n²)。
  • 优化点:可随机选择基准(避免最坏情况)。

欢迎关注 ❤

我们搞了一个免费的面试真题共享群,互通有无,一起刷题进步。

没准能让你能刷到自己意向公司的最新面试题呢。

感兴趣的朋友们可以加我微信:wangzhongyang1993,备注:sf面试群。


王中阳讲编程
833 声望321 粉丝