写点什么

字节的面试,感觉还挺简单的~

作者:王中阳Go
  • 2025-01-17
    湖南
  • 本文字数:3489 字

    阅读完需:约 11 分钟

字节的面试,感觉还挺简单的~

今天分享的是训练营的朋友在字节跳动的面试,新鲜出炉的还热乎着呢。题目都挺简单的,但是他的面试体验不太好,因为面试官问了两个类似的问题,感觉有点不认真。


下面是面试的内容:


面经详解

  • 简单介绍下你的项目

  • 介绍下教育平台考试模块的业务.包括

  • 题目的读写

  • 试卷的生成

  • 创建之后,试题如何存储

  • 试卷如何分发给考生

  • 考生如何提交试卷,你们如何收集试卷结果

  • 最后怎么判题


以下是对每个问题的回答:

前端接口使用 restful 格式,post 与 get 的区别是什么?

  • 功能用途

  • GET:用于获取资源,通常是从服务器检索数据,比如获取文章列表、用户信息等,不会对服务器上的资源进行修改。

  • POST:主要用于传输实体对象,常用于创建或更新资源,比如提交表单数据、上传文件、创建新用户等。

  • 参数传递

  • GET:将参数拼加到 URL 上进行传递,形成查询字符串,如http://example.com/api/user?id=123

  • POST:把请求参数写入到请求正文中传递,参数不会显示在 URL 中。

  • 缓存情况

  • GET:一般会被缓存,浏览器和代理服务器可能会缓存 GET 请求的结果,以提高性能。

  • POST:默认不进行缓存,每次请求都会发送到服务器进行处理。

  • 历史记录与书签

  • GET:请求的参数会保存在历史记录中,其地址可被收藏为书签。

  • POST:请求的参数不会保留到历史记录中,地址也不能被收藏为书签。

  • 安全性与幂等性

  • GET:相对不安全,因为参数在 URL 中可见,且通常用于获取数据,应是幂等的,多次请求结果相同。

  • POST:相对安全些,数据在请求体中,但仍需 HTTPS 加密敏感数据,不是幂等的,多次请求可能导致多次创建或更新资源。

HTTP 网络返回的状态码有哪些?

  • 1xx 系列:表示请求已被接受,需要继续处理。如100 Continue,客户端应当继续发送请求;101 Switching Protocols,服务器通知客户端采用不同的协议来完成请求。

  • 2xx 系列:代表请求已成功被服务器接收、理解、并接受。如200 OK,请求已成功;201 Created,请求已经被实现,有一个新的资源已建立;202 Accepted,服务器已接受请求,但尚未处理。

  • 3xx 系列:通常表示需要客户端采取进一步的操作才能完成请求,主要用于重定向。如301 Moved Permanently,被请求的资源已永久移动到新位置;302 Move Temporarily,请求的资源临时从不同的 uri 响应请求;304 Not Modified,客户端发送带条件的 get 请求且文档内容未改变。

  • 4xx 系列:一般表示客户端错误。如401 Unauthorized,用户需要提供身份验证凭据;403 Forbidden,用户已被禁止访问该网站;404 Not Found,未找到所请求的资源。

  • 5xx 系列:通常表示服务器内部错误。如500 Internal Server Error,网站出现严重错误;503 Service Unavailable,服务器维护或暂时不可用。

go 语言切片与数组的区别是什么?

  • 定义方式

  • 数组:在 Go 语言中,数组是具有固定长度的同类型元素的序列,定义时需要指定长度和元素类型,如var a [5]int

  • 切片:切片是对数组的一个连续片段的引用,它本身不存储数据,只是对底层数组的一种抽象,定义方式如var s []int

  • 长度与容量

  • 数组:长度是固定的,在定义时就确定了,不能动态改变。

  • 切片:长度可以动态变化,通过append()函数可以向切片中添加元素,自动扩容。切片还有容量的概念,容量通常大于或等于长度,表示切片可以容纳的元素数量。

  • 传递与赋值

  • 数组:在 Go 语言中,数组是值类型,当把一个数组赋值给另一个数组或作为函数参数传递时,会进行值拷贝,产生一个新的数组。

  • 切片:切片是引用类型,赋值和传递时只是复制了切片的引用,不会复制底层数组的数据,多个切片可以共享同一个底层数组。

  • 内存分配与效率

  • 数组:在内存中是连续分配的一段空间,大小固定,访问效率高,但在需要动态变化长度时效率较低,因为需要重新分配内存并复制数据。

  • 切片:切片的底层数组可能会根据需要动态扩容,扩容时可能会涉及到内存的重新分配和数据的复制,但在追加元素时一般比数组更灵活高效。

MySQL 实现并发安全避免两个事务同时对一个记录写操作的手段有哪些?

  • 悲观锁

  • 共享锁(S 锁):允许事务对数据进行读取操作,但不允许其他事务对该数据进行修改操作,在执行SELECT语句时可以使用LOCK IN SHARE MODE语句添加共享锁。

  • 排他锁(X 锁):事务获取排他锁后,其他事务既不能对该数据进行读取操作,也不能进行修改操作,在执行UPDATEDELETE等语句时会自动添加排他锁,也可以在SELECT语句中使用FOR UPDATE语句添加排他锁。

  • 乐观锁

  • 版本号机制:在表中添加一个版本号字段,每次更新数据时,版本号都会递增。在更新数据时,先查询出当前记录的版本号,然后在更新语句中加入版本号的判断条件,如果版本号与查询出的一致,则更新成功,否则更新失败。

  • 时间戳机制:类似于版本号机制,使用时间戳字段记录数据的最后更新时间,在更新数据时,先比较时间戳,只有当时间戳与查询出的一致时才允许更新。

  • 事务隔离级别

  • 可重复读(REPEATABLE READ):在该隔离级别下,一个事务在执行过程中多次读取同一数据时,会看到相同的数据值,即使其他事务对该数据进行了修改并提交,也不会影响当前事务的读取结果,从而避免了脏读、不可重复读等问题。

  • 串行化(SERIALIZABLE):最高的隔离级别,所有事务依次逐个执行,避免了并发冲突,但性能较差,一般在对数据一致性要求极高的场景下使用。

如何实现业务的幂等性(在 golang 代码中如何避免消息重复或处理已出现的消息重复)?

  • 使用唯一标识:在业务中为每一个请求或消息生成一个唯一的标识,如 UUID 等。在处理请求或消息之前,先检查该标识是否已经存在,如果存在则说明是重复消息,直接返回之前的处理结果或进行相应的处理,不再重复执行业务逻辑。

  • 数据库约束:利用数据库的唯一约束来保证数据的唯一性。例如,在插入数据时,如果违反了唯一约束,则说明该数据已经存在,此时可以根据具体情况进行相应的处理,如更新数据或直接返回错误信息等。

  • 分布式锁:在处理消息或请求时,使用分布式锁来保证同一时间只有一个实例在处理该消息或请求。可以使用 Redis 等分布式锁来实现,在获取锁成功后再进行业务处理,处理完成后释放锁,避免多个实例同时处理导致消息重复。

  • 消息队列的幂等性处理:如果使用消息队列来传递消息,可以在消息队列的消费者端进行幂等性处理。例如,在消息中添加一个唯一标识字段,消费者在处理消息时先检查该标识是否已经处理过,如果已经处理过则直接确认消息已消费,不再重复处理。

如何设置 redis 分布式锁?

  • 使用 SETNX 命令SETNX key value命令用于在指定的键不存在时,设置键的值。可以将锁的获取和释放操作封装成函数,在获取锁时,使用SETNX命令设置一个特定的键值对,如果返回 1 表示获取锁成功,否则表示锁已被其他客户端获取。在释放锁时,使用DEL命令删除该键。

  • 设置过期时间:为了防止客户端在获取锁后出现异常情况导致锁无法释放,可以在获取锁时同时设置一个过期时间,使用SET key value EX seconds命令,这样即使客户端出现异常,锁也会在过期时间后自动释放,避免死锁的发生。

  • 使用 Redlock 算法:Redlock 算法是一种更复杂的分布式锁实现方式,它通过在多个 Redis 节点上同时获取锁,只有当大多数节点都获取锁成功时,才认为获取锁成功,从而提高了分布式锁的可靠性和安全性。

编写代码:元素不重复的整数数组,返回该数组第二大的元素。

package main
import "fmt"
func secondLargest(nums []int) int { if len(nums) < 2 { panic("数组元素个数不足") } first := nums[0] second := nums[1] if first < second { first, second = second, first } for i := 2; i < len(nums); i++ { if nums[i] > first { second = first first = nums[i] } else if nums[i] > second && nums[i] < first { second = nums[i] } } return second}
func main() { nums := []int{5, 2, 8, 1, 9, 3} fmt.Println(secondLargest(nums))}
复制代码


代码解释


  1. 首先,检查数组长度是否小于 2,如果小于 2 则抛出异常,因为无法找到第二大元素。

  2. 初始化 firstsecond 变量,将 nums[0] 赋值给 firstnums[1] 赋值给 second。如果 first 小于 second,交换它们的值,保证 first 是最大的元素,second 是第二大的元素。

  3. 然后遍历数组中从索引 2 开始的元素:

  4. 如果当前元素比 first 大,将 first 的值赋给 second,将当前元素的值赋给 first,因为找到了更大的元素。

  5. 如果当前元素比 second 大且比 first 小,将当前元素的值赋给 second,因为找到了新的第二大元素。

欢迎关注 ❤

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


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


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

发布于: 刚刚阅读数: 3
用户头像

王中阳Go

关注

靠敲代码在北京买房的程序员 2022-10-09 加入

【微信】wangzhongyang1993【公众号】程序员升职加薪之旅【成就】InfoQ专家博主👍掘金签约作者👍B站&掘金&CSDN&思否等全平台账号:王中阳Go

评论

发布
暂无评论
字节的面试,感觉还挺简单的~_Go_王中阳Go_InfoQ写作社区