网易
文章目录
网易八股面试
八股文
golang:
1,不同包的多个init函数的运行时机(答得不好 没看过这里)
2,init和main函数的执行顺序 (init函数在main函数开始前执行)
3,如何删除切片中的某一个元素 (就说了一个通过append(a[:2],a[3:]…))
4,sync.Map{}怎么使用 (使用Store存)
5,怎么控制去并发操作map(加锁)
6,go的读写锁怎么工作 (一大段支支吾吾后说了读写互斥)
7,如何保存程序崩溃时的数据 (不会,说了日志,在项目中聊到recover我就没想到这)
8,多个并发操作对map进行读写,程序会发生什么(给了两个选项,a:会继续执行 b:程序会崩溃,选了a,结果现在一查发现是b)
9,超时处理 (在网上查到用context.WithTimeout更好,我说的time.After) 去监听 channel的一个超时事件
- context deadline 超时控制
- 通过 time.After
10,对一个已经关闭的channel读写会发生什么 (如果不空的话,先读数据,空的话读对应类型的零值, 写的话会出现panic)
11,开五个协程 全部执行一个函数,怎么保证协程执行完全部打印(使用sync.WaitGroup ) 1. 简单点用 WaitGroup 阻塞 5个协程 2. 基于channel, 开大小为5的channel, 然后 每个携程执行完成之后,发送一个事件
|
|
linux:
1,怎么去查询某一行的数据 (grep)
2,怎么汇总url,统计每个url (不会)
|
|
|
|
3,怎么查找进程 (ps)
4,怎么查找有go语言的进程 (pgrep go)
mysql:
1,对abc建立联合索引,他们的顺序重要么(重要,应把使用频率高的放在前面)
作者:牛客128067218号 链接: https://www.nowcoder.com/discuss/499307188142223360?sourceSSR=search 来源:牛客网
解题
GO基础
定义:Go 的每个包可以有多个 init 函数(甚至在一个文件内),用于初始化代码。 运行时机: 先初始化被依赖的包:如果包 A 依赖包 B,则 B 的 init 函数会在 A 的 init 函数前运行。 同一包内多个文件:按照编译器决定的文件顺序依次执行。 单文件多个 init 函数:按照代码顺序执行。
MVCC
MVCC(Multi-Version Concurrency Control,多版本并发控制) 是 MySQL InnoDB 存储引擎中实现高并发读写性能的关键技术。它通过为每一行数据保存多个版本,允许读操作和写操作并行进行,减少了锁的使用。
在 MySQL InnoDB 中,即使没有使用 SELECT … FOR UPDATE,默认的事务隔离级别 可重复读(REPEATABLE READ) 也能够解决幻读问题。这是由于 InnoDB 的 MVCC 和 Next-Key Lock 机制 的配合工作,即使在没有显式加锁的情况下,依然能够避免幻读的发生。
MVCC 的工作机制 隐藏的两个字段: 每行记录会存储两个额外的隐藏字段:
DB_TRX_ID:最近一次对该行修改的事务 ID。 DB_ROLL_PTR:回滚指针,指向 Undo Log 中的旧版本数据。 Undo Log:
当事务对数据进行更新时,旧版本会存储在 Undo Log 中,用于支持 MVCC 的一致性读。 事务 ID:
每个事务启动时,InnoDB 分配一个递增的事务 ID(TRX_ID),用来标识事务的版本。 两种一致性读:
当前读(Current Read): 当前读会读取最新版本的数据,并对数据加锁(如 SELECT … FOR UPDATE、UPDATE)。 快照读(Snapshot Read): 读取数据时基于事务开始时的快照视图,避免锁定数据(如普通的 SELECT)。
详细示例:幻读解决机制 假设有以下场景:
初始表数据:
sql
id | value 1 | 100 3 | 300 事务 1:
|
|
锁定了 id >= 2 的范围,包括 id=3 的行和 2~3 之间的间隙。 事务 2:
|
|
由于间隙锁,事务 2 在尝试插入 id=2 时会被阻塞,直到事务 1 提交。 总结:
通过 Next-Key Lock,MySQL 不仅锁定了现有行,还锁定了满足查询条件的间隙,从而防止了幻读。
案例
|
|
是的,在 MySQL InnoDB 中,如果事务的隔离级别是 可重复读(REPEATABLE READ) 或更低,SELECT * FROM table WHERE id >= 2
执行的确是 快照读(Snapshot Read)。这种情况下,即使在事务运行期间有新的数据插入,事务中的后续查询仍然基于事务开始时的快照视图,无法看到新插入的数据。
快照读的关键机制:MVCC
-
事务开始时创建快照:
- 当事务启动时,InnoDB 会为该事务生成一个 一致性视图(Consistent Read View),记录当前能看到的数据版本。
- 事务中的所有普通
SELECT
查询都会基于这个快照执行。
-
版本控制(MVCC 原理):
- 每条记录在 InnoDB 中都存储了多个版本(通过 Undo Log 实现)。
- 快照读查询根据事务的快照时间戳(事务 ID),仅读取那些在快照时间点已经提交的数据版本。
- 未提交的、更改中的数据对快照读不可见。
示例解释
假设表 table
中初始有以下数据:
|
|
操作过程:
-
事务 1 启动并执行第一次查询:
1 2
BEGIN; SELECT * FROM table WHERE id >= 2; -- 返回 id=3 的行
- 在事务开始时,InnoDB 创建了一个一致性快照。
- 查询结果:
id=3
。
-
事务 2 插入新记录并提交:
1 2 3
BEGIN; INSERT INTO table (id, value) VALUES (2, 200); COMMIT;
id=2
的新记录已经被提交,但对事务 1 来说不可见,因为事务 1 的快照视图没有包含这条记录。
-
事务 1 再次查询:
1
SELECT * FROM table WHERE id >= 2; -- 返回的仍然是快照数据
- 查询结果依旧是
id=3
,而不会包括id=2
。 - 原因是事务 1 的查询仍然基于事务开始时的快照。
- 查询结果依旧是
为什么快照读查询不到新插入的数据?
-
快照视图的隔离性:
- 当事务 1 开始时,它只看到在快照创建之前提交的所有数据版本。
- 新插入的数据即使提交了,也不在快照视图内。
-
避免“幻读”:
- 虽然没有加锁,快照读通过 MVCC 的机制实现了事务间的隔离性,保证了同一个事务的查询结果一致。
快照读 VS 当前读
类型 | 特点 | 是否加锁 |
---|---|---|
快照读 | 基于事务开始时的快照,读取的是固定的历史版本数据,查询结果一致。 | 否 |
当前读 | 读取最新版本的数据,可能会阻塞或被阻塞。例如 SELECT ... FOR UPDATE 和 UPDATE 等。 |
是 |
总结
- 当事务使用普通的
SELECT
查询(快照读)时,查询结果是基于事务开始时的快照视图。 - 即使在事务运行期间有其他事务插入或修改了数据,快照读查询的结果也不会变化,确保了事务的一致性。
- 下次查询
id >= 2
的结果仍然是最初快照中的内容,不会包含新插入的数据。这正是快照读的核心特性。
文章作者 lyr
上次更新 2024-02-02