8 Commits f76534f6b5 ... a4d4c7c21f

Auteur SHA1 Message Date
  seamew a4d4c7c21f 修改了面经 il y a 1 an
  seamew ab32931f89 修改了面经 il y a 1 an
  seamew db2f23bbf2 更新了面经 il y a 1 an
  seamew ec111d1a7c 更新面经 il y a 1 an
  seamew b487815f5b 更新面经 il y a 1 an
  seamew b920b61c39 修改了面经 il y a 2 ans
  seamew 9ebd0d5810 修改了面经 il y a 2 ans
  seamew 9abbbb2a2b 修改了面经 il y a 2 ans
100 fichiers modifiés avec 1341 ajouts et 383 suppressions
  1. 78 61
      Git学习笔记/git与vim常见指令集.md
  2. 17 280
      Git学习笔记/你可能会忽略的 Git 提交规范摘录.md
  3. 0 25
      Git学习笔记/开发规范.md
  4. 261 3
      后端/Java/JAVA高阶/JUC编程/线程池源码.md
  5. 66 0
      算法/排序/数字出现次数.md
  6. BIN
      算法/排序算法/assets/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMTUyMDUy,size_16,color_FFFFFF,t_70.png
  7. 51 1
      算法/排序算法/基本排序算法.md
  8. 3 0
      算法/贪心/求数组中比左边元素都大同时比右边元素都小的元素.md
  9. 4 0
      算法平台/改进.md
  10. BIN
      论文/assets/image-20230816145833671.png
  11. BIN
      论文/assets/image-20230816145844068.png
  12. BIN
      论文/assets/image-20230816145853300.png
  13. BIN
      论文/assets/image-20230816153747750.png
  14. 11 0
      论文/petri网.md
  15. 13 0
      面经/2023年暑期实习/字节一面.md
  16. 20 0
      面经/2023年暑期实习/快手.md
  17. 6 0
      面经/2023年暑期实习/百度.md
  18. 23 7
      面经/工作/秋招.md
  19. 64 1
      面经/问答/JVM.md
  20. 215 0
      面经/问答/K8S.md
  21. 509 5
      面经/问答/Mysql.md
  22. BIN
      面经/问答/assets/03eacec67cc58ff8d5819d0872ddd41e.png
  23. BIN
      面经/问答/assets/04163db3b7ca4b4c8fbfdf4e7253a98ftplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  24. BIN
      面经/问答/assets/056c87751b9dd7b56f4264240fe96d00.png
  25. BIN
      面经/问答/assets/13e4361407ba46979e802eaa654dcf67.png
  26. BIN
      面经/问答/assets/1418b09699fe4614a594a565c55055d5tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  27. BIN
      面经/问答/assets/16c1e0e2878c44dctplv-t2oaga2asx-jj-mark3024000q75.awebp
  28. BIN
      面经/问答/assets/16c1e0e28889eafftplv-t2oaga2asx-jj-mark3024000q75.awebp
  29. BIN
      面经/问答/assets/16c1e0e289a351b2tplv-t2oaga2asx-jj-mark3024000q75.awebp
  30. BIN
      面经/问答/assets/16c1e0e289f9213etplv-t2oaga2asx-jj-mark3024000q75.awebp
  31. BIN
      面经/问答/assets/16c1e0e28aee99a1tplv-t2oaga2asx-jj-mark3024000q75.awebp
  32. BIN
      面经/问答/assets/16c1e0e2ca893b49tplv-t2oaga2asx-jj-mark3024000q75.awebp
  33. BIN
      面经/问答/assets/16c1e0e2d7df4fbftplv-t2oaga2asx-jj-mark3024000q75.awebp
  34. BIN
      面经/问答/assets/16c1e0e2db1c4812tplv-t2oaga2asx-jj-mark3024000q75-16934721993069.awebp
  35. BIN
      面经/问答/assets/16c1e0e2db1c4812tplv-t2oaga2asx-jj-mark3024000q75.awebp
  36. BIN
      面经/问答/assets/16c1e0e2e2a2835etplv-t2oaga2asx-jj-mark3024000q75.awebp
  37. BIN
      面经/问答/assets/16c1e0e2e507aec0tplv-t2oaga2asx-jj-mark3024000q75.awebp
  38. BIN
      面经/问答/assets/16c1e0e3178398fctplv-t2oaga2asx-jj-mark3024000q75.awebp
  39. BIN
      面经/问答/assets/16c1e26a5ecf086etplv-t2oaga2asx-jj-mark3024000q75.awebp
  40. BIN
      面经/问答/assets/1cc7401143e79383ead96582ac11b615.png
  41. BIN
      面经/问答/assets/20201104163915661.png
  42. BIN
      面经/问答/assets/20201104164026393.png
  43. BIN
      面经/问答/assets/20201104164057943.png
  44. BIN
      面经/问答/assets/202308021211012.jpeg
  45. BIN
      面经/问答/assets/202308021212079.jpeg
  46. BIN
      面经/问答/assets/202308021212511.jpeg
  47. BIN
      面经/问答/assets/202308021218967.jpeg
  48. BIN
      面经/问答/assets/2164474-20210716210057908-1704850787.png
  49. BIN
      面经/问答/assets/22c7fe97ce5d3c382b08d83a4d8a5b96.png
  50. BIN
      面经/问答/assets/2306520394.png
  51. BIN
      面经/问答/assets/24-先来先服务.jpg
  52. BIN
      面经/问答/assets/25-最短作业优先算法.jpg
  53. BIN
      面经/问答/assets/2535cfeb9cfb44d4a0a04506f09f7485tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  54. BIN
      面经/问答/assets/26-响应比公式.jpg
  55. BIN
      面经/问答/assets/26f88373d8454682b9e0c1d4fd1611b4-20230309233114856.png
  56. BIN
      面经/问答/assets/27-时间片轮询.jpg
  57. BIN
      面经/问答/assets/28-多级队列.jpg
  58. BIN
      面经/问答/assets/2802786ab4f52c1e248904e5cef33a74.png
  59. BIN
      面经/问答/assets/2ae0ed790c7e7403f215acb2bd82e884.png
  60. BIN
      面经/问答/assets/2b7231b6aabb9a9a2e2390ab3a280b2d-20230309232920063.png
  61. BIN
      面经/问答/assets/2db4831516b9a8b79f833cf0593c1f12.png
  62. BIN
      面经/问答/assets/2e2b95eebf60b6d03f6c1476f4d7c697.png
  63. BIN
      面经/问答/assets/30c2c70721c12f9c140358fbdc5f2282.png
  64. BIN
      面经/问答/assets/316b81a42ea843a192cc2f3578fbdb81tplv-k3u1fbpfcp-zoom-in-crop-mark1512000-16927837871897.awebp
  65. BIN
      面经/问答/assets/316b81a42ea843a192cc2f3578fbdb81tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  66. BIN
      面经/问答/assets/31b9745a2fa94fb693a7ea1257aa5f7ftplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  67. BIN
      面经/问答/assets/33f858652afc4be6bb1d7b1f1dc33eaatplv-k3u1fbpfcp-zoom-in-crop-mark1512000-169278452952817.awebp
  68. BIN
      面经/问答/assets/33f858652afc4be6bb1d7b1f1dc33eaatplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  69. BIN
      面经/问答/assets/35820959e8cf4376391c427ed7f81495.png
  70. BIN
      面经/问答/assets/3a6cb4e3f27241d3b09b4766bb0b1124.png
  71. BIN
      面经/问答/assets/3层跳表-跨度.drawio.png
  72. BIN
      面经/问答/assets/3层跳表-跨度.png
  73. BIN
      面经/问答/assets/454a8228a6549176ad7e0484fba3c92b.png
  74. BIN
      面经/问答/assets/47e6c8fbc17fd6c89bdfcb5eedaaacff.png
  75. BIN
      面经/问答/assets/4845008abadaa871613873f5ffdcb542.png
  76. BIN
      面经/问答/assets/4d850bfe8d712d3d67ff13e59b919452.png
  77. BIN
      面经/问答/assets/4ef8691d67eb1eb53217099d0a691eb5.png
  78. BIN
      面经/问答/assets/516738c4058cdf9109e40a7812ef4239.png
  79. BIN
      面经/问答/assets/517e2f7939394b3ca35936702a107f07tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  80. BIN
      面经/问答/assets/559260f5ef944cd1a146d07308275b89tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  81. BIN
      面经/问答/assets/5e9e65a4a59b3688fa37cadbd87bb5ac.png
  82. BIN
      面经/问答/assets/60d6b91f49ac4d11bee43f86f33566d6tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  83. BIN
      面经/问答/assets/6a68be69f6b64ad1a8df234d9f0772detplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  84. BIN
      面经/问答/assets/775865f6bd894dfba8d373ee54d79af1.png
  85. BIN
      面经/问答/assets/788acb3c73174c42b603fe67e96c89f5tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  86. BIN
      面经/问答/assets/7d45e677f6c2428d9b9db7022416fe26tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  87. BIN
      面经/问答/assets/80a2bcb823e04e05a10c8f19de2930b9tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  88. BIN
      面经/问答/assets/8febac10b14bed16cb96d1d944cd08da.png
  89. BIN
      面经/问答/assets/955fdfb94c234e32939c76954fd28a56tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  90. BIN
      面经/问答/assets/98987d9417b2bab43087f45fc959d32a-20230309232253633.png
  91. BIN
      面经/问答/assets/9ebde5c11ad69447314c216acf188fc8.png
  92. BIN
      面经/问答/assets/a3e7d217ecb825e94bdc577a467eb29d.png
  93. BIN
      面经/问答/assets/a6e0e622b7384ac78f733e471b280c27tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  94. BIN
      面经/问答/assets/a851f56a384b4a0f9da76644d645ae1ftplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  95. BIN
      面经/问答/assets/arch-x-reduce-2.png
  96. BIN
      面经/问答/assets/arch-x-reduce-3.png
  97. BIN
      面经/问答/assets/arch-x-reduce-31-169347359783720.png
  98. BIN
      面经/问答/assets/b52e004bd4654cb1b51cdb409182156ftplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp
  99. BIN
      面经/问答/assets/b5681d905102439aa1a40412100da566.png
  100. BIN
      面经/问答/assets/c55029a32a6448d9aa35bb3de6efcecatplv-k3u1fbpfcp-zoom-in-crop-mark4536000.awebp

+ 78 - 61
Git学习笔记/git与vim常见指令集.md

@@ -2,6 +2,7 @@
 
 # 常用Git命令总结
 
+```shell
 - git config --global user.name "你的名字" 让你全部的Git仓库绑定你的名字
 - git config --global user.email "你的邮箱" 让你全部的Git仓库绑定你的邮箱
 - git init 初始化你的仓库
@@ -48,6 +49,9 @@
 - git config --global color.ui true 让Git显示颜色,会让命令输出看起来更醒目
 - git add -f <file> 强制提交已忽略的的文件
 - git check-ignore -v <file> 检查为什么Git会忽略该文件
+```
+
+
 
 
 
@@ -55,78 +59,37 @@
 
 ## VIM 进入和退出命令
 
-> 常用命令是ESC,然后:wq(保存并退出),:q!(不保存并强制退出),i进入vim模式。另外还有其它的,我可能都不会用到。。。
-> 按ESC键 跳到命令模式,然后:
+> **常用命令是ESC,然后:wq(保存并退出),:q!(不保存并强制退出),i进入vim模式。另外还有其它的,我可能都不会用到。。。**
+> **按ESC键 跳到命令模式,然后:**
 
-1. **:w 保存文件但不退出vi**
-2. **:w file 将修改另外保存到file中,不退出vi**
-3. **:w! 强制保存,不推出vi**
-4. **:wq 保存文件并退出vi**
-5. **:wq! 强制保存文件,并退出vi**
-6. **q: 不保存文件,退出vi**
-7. **:q! 不保存文件,强制退出vi**
-8. **:e! 放弃所有修改,从上次保存文件开始再编辑**
+```shell
+1. :w 保存文件但不退出vi
+2. :w file 将修改另外保存到file中,不退出vi
+3. :w! 强制保存,不推出vi
+4. :wq 保存文件并退出vi
+5. :wq! 强制保存文件,并退出vi
+6. q: 不保存文件,退出vi
+7. :q! 不保存文件,强制退出vi
+8. :e! 放弃所有修改,从上次保存文件开始再编辑
+```
 
 ## 命令历史
 
+```shell
 以:和/开头的命令都有历史纪录,可以首先键入:或/然后按上下箭头来选择某个历史命令。
-
-## 启动vim
-
-在命令行窗口中输入以下命令即可
-
-vim 直接启动vim
-
-vim filename 打开vim并创建名为filename的文件
-
-## 文件命令
-
-打开单个文件
-
-vim file
-
-同时打开多个文件
-
-vim file1 file2 file3 ...
-
-在vim窗口中打开一个新文件
-
-:open file
-
-在新窗口中打开文件
-
-:split file
-
-切换到下一个文件
-
-:bn
-
-切换到上一个文件
-
-:bp
-
-查看当前打开的文件列表,当前正在编辑的文件会用[]括起来。
-
-:args
-
-打开远程文件,比如ftp或者share folder
-
-:e ftp://192.168.10.76/abc.txt
-
-:e \\qadrive\test\1.txt
-
-## vim的模式
-
-正常模式(按Esc或Ctrl+[进入) 左下角显示文件名或为空
-插入模式(按i键进入) 左下角显示--INSERT--
-可视模式(不知道如何进入) 左下角显示--VISUAL--
+```
 
 ## 导航命令
 
+```shell
 % 括号匹配
+```
+
+
 
 ## 插入命令
 
+```shell
 i 在当前位置生前插入
 
 I 在当前行首插入
@@ -138,9 +101,13 @@ A 在当前行尾插入
 o 在当前行之后插入一行
 
 O 在当前行之前插入一行
+```
+
+
 
 ## 查找命令
 
+```shell
 /text  查找text,按n健查找下一个,按N健查找前一个。
 
 ?text  查找text,反向查找,按n健查找下一个,按N健查找前一个。
@@ -162,9 +129,13 @@ vim中有一些特殊字符在查找时需要转义  .*[]^%/?~$
 :set incsearch  逐步搜索模式,对当前键入的字符进行搜索而不必等待键入完成。
 
 :set wrapscan  重新搜索,在搜索到文件头或尾时,返回继续搜索,默认开启。
+```
+
+
 
 ## 替换命令
 
+```shell
 ra 将当前字符替换为a,当期字符即光标所在字符。
 
 s/old/new/ 用old替换new,替换当前行的第一个匹配
@@ -178,9 +149,13 @@ s/old/new/g 用old替换new,替换当前行的所有匹配
 :10,20 s/^/  /g 在第10行知第20行每行前面加四个空格,用于缩进。
 
 ddp 交换光标所在行和其下紧邻的一行。
+```
+
+
 
 ## 移动命令
 
+```shell
 h 左移一个字符
 l 右移一个字符,这个命令很少用,一般用w代替。
 k 上移一个字符
@@ -224,15 +199,23 @@ Ctrl + u 向上滚动半屏
 Ctrl + f 向下滚动一屏
 
 Ctrl + b 向上滚动一屏
+```
+
+
 
 ## 撤销和重做
 
+```shell
 u 撤销(Undo)
 U 撤销对整行的操作
 Ctrl + r 重做(Redo),即撤销的撤销。
+```
+
+
 
 ## 删除命令
 
+```shell
 x 删除当前字符
 
 3x 删除当前光标开始向后三个字符
@@ -266,9 +249,13 @@ jdG(jd shift + g)  删除当前行之后所有行(不包括当前行)
 :1,$d 删除所有行
 
 J(shift + j)  删除两行之间的空行,实际上是合并两行。
+```
+
+
 
 ## 拷贝和粘贴
 
+```shell
 yy 拷贝当前行
 
 nyy 拷贝当前后开始的n行,比如2yy拷贝当前行及其下一行。
@@ -286,9 +273,13 @@ shift+p 在当前行前粘贴
 ddp交换当前行和其下一行
 
 xp交换当前字符和其后一个字符
+```
+
+
 
 ## 剪切命令
 
+```shell
 正常模式下按v(逐字)或V(逐行)进入可视模式,然后用jklh命令移动即可选择某些行或字符,再按d即可剪切
 
 ndd 剪切当前行之后的n行。利用p命令可以对剪切的内容进行粘贴
@@ -296,9 +287,13 @@ ndd 剪切当前行之后的n行。利用p命令可以对剪切的内容进行
 :1,10d 将1-10行剪切。利用p命令可将剪切后的内容进行粘贴。
 
 :1, 10 m 20 将第1-10行移动到第20行之后。
+```
+
+
 
 ## 退出命令
 
+```shell
 :wq 保存并退出
 
 ZZ 保存并退出
@@ -306,9 +301,13 @@ ZZ 保存并退出
 :q! 强制退出并忽略所有更改
 
 :e! 放弃所有修改,并打开原来文件。
+```
+
+
 
 ## 窗口命令
 
+```shell
 :split或new 打开一个新窗口,光标停在顶层的窗口上
 
 :split file或:new file 用新窗口打开文件
@@ -336,9 +335,13 @@ ZZ 保存并退出。
 录制宏
 
 按q键加任意字母开始录制,再按q键结束录制(这意味着vim中的宏不可嵌套),使用的时候@加宏名,比如qa。。。q录制名为a的宏,@a使用这个宏。
+```
+
+
 
 ## 执行shell命令
 
+```shell
 :!command
 
 :!ls 列出当前目录下文件
@@ -348,9 +351,13 @@ ZZ 保存并退出。
 :!perl script.pl 执行perl脚本,可以不用退出vim,非常方便。
 
 :suspend或Ctrl - Z 挂起vim,回到shell,按fg可以返回vim。
+```
+
+
 
 ## 注释命令
 
+```shell
 perl程序中#开始的行为注释,所以要注释某些行,只需在行首加入#
 
 3,5 s/^/#/g 注释第3-5行
@@ -360,9 +367,13 @@ perl程序中#开始的行为注释,所以要注释某些行,只需在行首
 1,$ s/^/#/g 注释整个文档。
 
 :%s/^/#/g 注释整个文档,此法更快。
+```
+
+
 
 ## 帮助命令
 
+```shell
 :help or F1 显示整个帮助
 :help xxx 显示xxx的帮助,比如 :help i, :help CTRL-[(即Ctrl+[的帮助)。
 :help 'number' Vim选项的帮助用单引号括起
@@ -370,9 +381,13 @@ perl程序中#开始的行为注释,所以要注释某些行,只需在行首
 :help -t Vim启动参数的帮助用-
 :help i_<Esc> 插入模式下Esc的帮助,某个模式下的帮助用模式_主题的模式
 帮助文件中位于||之间的内容是超链接,可以用Ctrl+]进入链接,Ctrl+o(Ctrl + t)返回
+```
+
+
 
 ## 其他非编辑命令
 
+```shell
 . 重复前一次命令
 
 :set ruler?  查看是否设置了ruler,在.vimrc中,使用set命令设制的选项都可以通过这个命令查看
@@ -390,4 +405,6 @@ $ vimtutor
 :syntax 列出已经定义的语法项
 :syntax clear 清除已定义的语法规则
 :syntax case match 大小写敏感,int和Int将视为不同的语法元素
-:syntax case ignore 大小写无关,int和Int将视为相同的语法元素,并使用同样的配色方案
+:syntax case ignore 大小写无关,int和Int将视为相同的语法元素,并使用同样的配色方案
+```
+

+ 17 - 280
Git学习笔记/你可能会忽略的 Git 提交规范摘录.md

@@ -1,289 +1,26 @@
-# #目录
-
->[TOC]
-
 # 本人笔记提交标准
 
-```jsx
-docs: 新建知识点笔记
-feat:新增知识点(feature)。
-update:对于某部分知识点的更新修改(不是勘误,如更新目录索引、某正确知识点补全等操作)
-fix:勘误,修正知识点错误等操作
-style:如文档内样式调整,格式调整等不影响笔记内容的操作 (如删除多余资源,如无用的图片,无用语句删除等)
-refactor:笔记重构与优化(主要就是目录变动、笔记文件结构调整、文件名更改等操作)
-//举例
-docs(算法):新建数据结构与算法知识点笔记
-feat(前端-promise): 新增笔记中async+await+promise知识点笔记
-fix(前端-微信小程序):更正笔记中对于自定义组件描述的不恰当处
-refactor(前端):对于前端笔记部分文件目录进行重构调整
-style(后台-java):进行对该笔记中笔记格式与样式调整 或 进行对该笔记中多余图片展示资源的删除
-update:(README):笔记目录索引更新-新增小程序自封装组件笔记索引
-```
-
-
-
-# 你可能会忽略的 Git 提交规范
-
-一直是 ESLint 的忠实用户,深知规范的重要性。然而,在新项目交接中,我被 Git Commit 规范逼疯了。才意识到自己的疏忽,于是便有了一探究竟的想法。
-
-#### 一、为什么需要规范?
-
-无规矩不成方圆,编程也一样。
-
-如果你有一个项目,从始至终都是自己写,那么你想怎么写都可以,没有人可以干预你。可是如果在团队协作中,大家都张扬个性,那么代码将会是一团糟,好好的项目就被糟践了。不管是开发还是日后维护,都将是灾难。
-
-这时候,有人提出了何不统一标准,大家都按照这个标准来。于是 `ESLint`,`JSHint` 等代码工具如雨后春笋般涌现,成为了项目构建的必备良品。
-
-`Git Commit` 规范可能并没有那么夸张,但如果你在版本回退的时候看到一大段糟心的 `Commit`,恐怕会懊恼不已吧。所以,严格遵守规范,利人利己。
-
-#### 二、具体规则
-
-先来看看公式:
-
-```
-<type>(<scope>): <subject>
-```
-
-
-
-- type
-
-  - 用于说明
-
-     
-
-    ```
-    commit
-    ```
-
-     
-
-    的类别,只允许使用下面7个标识。
-
-    ```jsx
-    feat:新功能(feature)。
-    fix/to:修复bug,可以是QA发现的BUG,也可以是研发自己发现的BUG。
-    fix:产生diff并自动修复此问题。适合于一次提交直接修复问题
-    to:只产生diff不自动修复此问题。适合于多次提交。最终修复问题提交时使用fix
-    docs:文档(documentation)。
-    style:格式(不影响代码运行的变动)。
-    refactor:重构(即不是新增功能,也不是修改bug的代码变动)。
-    perf:优化相关,比如提升性能、体验。
-    test:增加测试。
-    chore:构建过程或辅助工具的变动。
-    revert:回滚到上一个版本。
-    merge:代码合并。
-    sync:同步主线或分支的Bug。
-    ```
-
-- scope
-
-  - 用于说明 `commit` 影响的范围,比如数据层、控制层、视图层等等,视项目不同而不同。
-
-- subject
-
-  - 是
-
-     
-
-    ```
-    commit
-    ```
-
-     
-
-    目的的简短描述,不超过50个字符。
-
-    ```
-    1.以动词开头,使用第一人称现在时,比如change,而不是changed或changes
-    2.第一个字母小写
-    3.结尾不加句号(.)
-    ```
-
-规范参考自阮一峰老师的文章:[Commit message 和 Change log 编写指南](http://www.ruanyifeng.com/blog/2016/01/commit_message_change_log.html)。
-
-#### 三、异常处理
-
-我们先来看看这个异常提醒:
-
-```
-INVALID COMMIT MSG: does not match "<type>(<scope>): <subject>" !
-jartto:fix bug
-```
-
-
-
-这里之所以报出这个警告,是因为我的提交出现了两个问题:
-其一,使用了规范外的关键字;
-其二,很细节的问题,jartto:后少了空格;
-
-这时候我才回忆起来,当时提交一直失败,情急之下直接强制提交,所以以后的提交都会抱出这个异常。大致意思就是:
-
-你的之前的 Commit 不合格~你的之前的 Commit 不合格~你的之前的 Commit 不合格
-
-这时候就很烦了,我们只能去将之前的错误修正,那么如何操作呢?
-
-#### 四、如何修改之前的 commit 信息?
-
-其实并不复杂,我们只需要这样做:
-1、将当前分支无关的工作状态进行暂存
-
-```
-git stash
-```
-
-
-
-2、将 `HEAD` 移动到需要修改的 `commit` 上
-
-```
-git rebase 9633cf0919^ --interactive
-```
-
+**分支命名**:日期_姓名首字母缩写_功能单词,如:`210804_xfg_buildFramework`
 
+**提交规范**:`作者,type: desc` 如:`孙浩博,fix:修复查询用户信息逻辑问题` *参考Commit message 规范*
 
-3、找到需要修改的 `commit` ,将首行的 `pick` 改成 `edit`
-4、开始着手解决你的 `bug`
-5、 `git add` 将改动文件添加到暂存
-6、 `git commit –amend` 追加改动到提交
-7、`git rebase –continue` 移动 `HEAD` 回最新的 `commit`
-8、恢复之前的工作状态
-
-```
-git stash pop
-```
-
-
-
-大功告成,是不是想把整个 Commit 都修改一遍,逃~
-
-此处参考自:[修改 Commit 日志和内容](https://www.aliyun.com/jiaocheng/125261.html)
-
-#### 五、项目中使用
-
-这时候问题又来了,为什么我提交的时候会有警告,这个又是如何做到的呢?
-
-这时候,我们需要一款 `Node` 插件 `validate-commit-msg` 来检查项目中 `Commit message` 是否规范。
-
-1.首先,安装插件:
-
-```
-npm install --save-dev validate-commit-msg
-```
-
+```shell
+# 主要type
+feat:     增加新功能
+fix:      修复bug
 
+# 特殊type
+docs:     只改动了文档相关的内容
+style:    不影响代码含义的改动,例如去掉空格、改变缩进、增删分号
+build:    构造工具的或者外部依赖的改动,例如webpack,npm
+refactor: 代码重构时使用
+revert:   执行git revert打印的message
 
-2.使用方式一,建立 `.vcmrc` 文件:
-
-```
-{
-  "types": ["feat", "fix", "docs", "style", "refactor", "perf", "test", "build", "ci", "chore", "revert"],
-  "scope": {
-    "required": false,
-    "allowed": ["*"],
-    "validate": false,
-    "multiple": false
-  },
-  "warnOnFail": false,
-  "maxSubjectLength": 100,
-  "subjectPattern": ".+",
-  "subjectPatternErrorMsg": "subject does not match subject pattern!",
-  "helpMessage": "",
-  "autoFix": false
-}
-```
-
-
-
-3.使用方式二:写入 `package.json`
-
-```
-{
-  "config": {
-    "validate-commit-msg": {
-      /* your config here */
-    }
-  }
-}
+# 暂不使用type
+test:     添加测试或者修改现有测试
+perf:     提高性能的改动
+ci:       与CI(持续集成服务)有关的改动
+chore:    不修改src或者test的其余修改,例如构建过程或辅助工具的变动
 ```
 
 
-
-4.可是我们如果想自动使用 [`ghooks`](https://www.npmjs.com/package/ghooks) 钩子函数呢?
-
-```
-{
-  …
-  "config": {
-    "ghooks": {
-      "pre-commit": "gulp lint",
-      "commit-msg": "validate-commit-msg",
-      "pre-push": "make test",
-      "post-merge": "npm install",
-      "post-rewrite": "npm install",
-      …
-    }
-  }
-  …
-}
-```
-
-
-
-在 `ghooks` 中我们可以做很多事情,当然不只是 `validate-commit-msg` 哦。
-
-更多细节请参考:[validate-commit-msg](https://github.com/conventional-changelog-archived-repos/validate-commit-msg)
-
-#### 六、Commit 规范的作用
-
-1.提供更多的信息,方便排查与回退;
-2.过滤关键字,迅速定位;
-3.方便生成文档;
-
-#### 七、生成 Change log
-
-正如[上文](http://jartto.wang/2018/07/08/git-commit/)提到的生成文档,如果我们的提交都按照规范的话,那就很简单了。生成的文档包括以下三个部分:
-
-- New features
-- Bug fixes
-- Breaking changes.
-
-每个部分都会罗列相关的 `commit` ,并且有指向这些 `commit` 的链接。当然,生成的文档允许手动修改,所以发布前,你还可以添加其他内容。
-
-这里需要使用工具 [Conventional Changelog](https://github.com/conventional-changelog/conventional-changelog) 生成 `Change log` :
-
-```
-npm install -g conventional-changelog
-cd jartto-domo
-conventional-changelog -p angular -i CHANGELOG.md -w
-```
-
-
-
-为了方便使用,可以将其写入 `package.json` 的 `scripts` 字段。
-
-```
-{
-  "scripts": {
-    "changelog": "conventional-changelog -p angular -i CHANGELOG.md -w -r 0"
-  }
-}
-```
-
-
-
-这样,使用起来就很简单了:
-
-```
-npm run changelog
-```
-
-
-
-到这里,我们所有的问题都搞明白了,🍻Cheers~
-
-#### 八、总结
-
-看完文章,你还会如此放荡不羁吗?你还会随心所欲的编写 `Commit` 吗?你还会如此 `git commit -m "hello jartto"`提交吗?
-
-答案是否定的,因为使用了钩子函数,你没有机会了,否则将是无穷无尽的恢复 `Commit`。这倒可以养成良好的提交习惯,🙈~

+ 0 - 25
Git学习笔记/开发规范.md

@@ -1,25 +0,0 @@
-### 开发规范
-
-**分支命名**:日期_姓名首字母缩写_功能单词,如:`220804_shb_redisCache`
-
-**提交规范**:`作者,type: desc` 如:`seamew,feat:增加redis缓存` *参考Commit message 规范*
-
-```
-# 主要type
-feat:     增加新功能
-fix:      修复bug
-
-# 特殊type
-docs:     只改动了文档相关的内容
-style:    不影响代码含义的改动,例如去掉空格、改变缩进、增删分号
-build:    构造工具的或者外部依赖的改动,例如webpack,npm
-refactor: 代码重构时使用
-revert:   执行git revert打印的message
-
-# 暂不使用type
-test:     添加测试或者修改现有测试
-perf:     提高性能的改动
-ci:       与CI(持续集成服务)有关的改动
-chore:    不修改src或者test的其余修改,例如构建过程或辅助工具的变动
-```
-

+ 261 - 3
后端/Java/JAVA高阶/JUC编程/线程池源码.md

@@ -236,7 +236,7 @@ private final class Worker extends AbstractQueuedSynchronizer implements Runnabl
 }
 ```
 
-#### runWorker方法
+### runWorker方法
 
 ```Java
 final void runWorker(Worker w) {
@@ -282,7 +282,7 @@ final void runWorker(Worker w) {
 }
 ```
 
-#### 从任务队列中取出一个任务
+### 从任务队列中取出一个任务
 
 ```Java
 private Runnable getTask() {
@@ -336,7 +336,7 @@ private Runnable getTask() {
 > 3. 线程池线程数大于最大线程数
 > 4. 线程可以被超时回收的情况下等待新任务超时
 
-#### 工作线程退出
+### 工作线程退出
 
 ```Java
 private void processWorkerExit(Worker w, boolean completedAbruptly) {
@@ -377,3 +377,261 @@ private void processWorkerExit(Worker w, boolean completedAbruptly) {
     }
 }
 ```
+
+### 工作线程如何回收
+
+```java
+    private Runnable getTask() {
+        boolean timedOut = false; // Did the last poll() time out?
+
+        for (;;) {
+            int c = ctl.get();
+            int rs = runStateOf(c);
+
+            // Check if queue empty only if necessary.
+            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
+                decrementWorkerCount();
+                return null;
+            }
+
+            int wc = workerCountOf(c);
+
+            // Are workers subject to culling?
+            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
+
+            if ((wc > maximumPoolSize || (timed && timedOut))
+                && (wc > 1 || workQueue.isEmpty())) {
+                if (compareAndDecrementWorkerCount(c))
+                    return null;
+                continue;
+            }
+
+            try {
+                // 通过时间进行判断,如果超时返回false
+                Runnable r = timed ?
+                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
+                    workQueue.take();
+                if (r != null)
+                    return r;
+                timedOut = true;
+            } catch (InterruptedException retry) {
+                timedOut = false;
+            }
+        }
+    }
+
+```
+
+```java
+private void processWorkerExit(Worker w, boolean completedAbruptly) {
+    // 如果completedAbruptly为true则表示任务执行过程中抛出了未处理的异常
+    // 所以还没有正确地减少worker计数,这里需要减少一次worker计数
+    if (completedAbruptly) 
+        decrementWorkerCount();
+
+    final ReentrantLock mainLock = this.mainLock;
+    mainLock.lock();
+    try {
+        // 把将被销毁的线程已完成的任务数累加到线程池的完成任务总数上
+        completedTaskCount += w.completedTasks;
+        // 这段代码就会减少工作线程
+        workers.remove(w); // 从工作线程集合中移除该工作线程
+    } finally {
+        mainLock.unlock();
+    }
+
+    // 尝试结束线程池
+    tryTerminate();
+
+    int c = ctl.get();
+    // 如果是RUNNING 或 SHUTDOWN状态
+    if (runStateLessThan(c, STOP)) {
+        // worker是正常执行完
+        if (!completedAbruptly) {
+            // 如果允许核心线程超时则最小线程数是0,否则最小线程数等于核心线程数
+            int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
+            // 如果阻塞队列非空,则至少要有一个线程继续执行剩下的任务
+            if (min == 0 && ! workQueue.isEmpty())
+                min = 1;
+            // 如果当前线程数已经满足最小线程数要求,则不需要再创建替代线程
+            if (workerCountOf(c) >= min)
+                return; // replacement not needed
+        }
+        // 重新创建一个worker来代替被销毁的线程
+        addWorker(null, false);
+    }
+}
+```
+
+##  如何中断
+
+### 中断别人
+
+```java
+private void processWorkerExit(Worker w, boolean completedAbruptly) {
+    // 尝试结束线程池
+    // 这里会中断别人
+    tryTerminate();
+}
+```
+
+### 具体实现
+
+```java
+    final void tryTerminate() {
+        for (;;) {
+            int c = ctl.get();
+            if (isRunning(c) ||
+                runStateAtLeast(c, TIDYING) ||
+                (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
+                return;
+            if (workerCountOf(c) != 0) { // Eligible to terminate
+                // 中断 ONLY_ONE = false
+                interruptIdleWorkers(ONLY_ONE);
+                return;
+            }
+
+            final ReentrantLock mainLock = this.mainLock;
+            mainLock.lock();
+            try {
+                if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
+                    try {
+                        terminated();
+                    } finally {
+                        ctl.set(ctlOf(TERMINATED, 0));
+                        termination.signalAll();
+                    }
+                    return;
+                }
+            } finally {
+                mainLock.unlock();
+            }
+            // else retry on failed CAS
+        }
+    }
+```
+
+```java
+    private void interruptIdleWorkers(boolean onlyOne) {
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            for (Worker w : workers) {
+                Thread t = w.thread;
+                if (!t.isInterrupted() && w.tryLock()) {
+                    try {
+                        // 前面已经被中断了,中断别人,相当于链式的中断
+                        t.interrupt();
+                    } catch (SecurityException ignore) {
+                    } finally {
+                        w.unlock();
+                    }
+                }
+                if (onlyOne)
+                    break;
+            }
+        } finally {
+            mainLock.unlock();
+        }
+    }
+```
+
+### 唤醒
+
+```java
+    private Runnable getTask() {
+        boolean timedOut = false; // Did the last poll() time out?
+
+        for (;;) {
+            int c = ctl.get();
+            int rs = runStateOf(c);
+
+            // Check if queue empty only if necessary.
+            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
+                decrementWorkerCount();
+                return null;
+            }
+
+            int wc = workerCountOf(c);
+
+            // Are workers subject to culling?
+            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
+
+            if ((wc > maximumPoolSize || (timed && timedOut))
+                && (wc > 1 || workQueue.isEmpty())) {
+                if (compareAndDecrementWorkerCount(c))
+                    return null;
+                continue;
+            }
+
+            try {
+                // 抛出异常会重置状态
+                Runnable r = timed ?
+                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
+                    workQueue.take();
+                if (r != null)
+                    return r;
+                timedOut = true;
+            } catch (InterruptedException retry) {
+                timedOut = false;
+            }
+        }
+    }
+```
+
+### 如果直接使用shutdown函数
+
+> 如果线程被中断会立即停止该线程在执行的任务吗?
+>
+> interrupt() 方法并不像在 for 循环语句中使用 break 语句那样干脆,马上就停止循环。调用 interrupt() 方法仅仅是在当前线程中打一个停止的标记,并不是真的停止线程。
+
+1. Running 状态,任务已全部完成,线程在阻塞等待。在 Running 状态进入 shutdown 状态。
+
+很简单,中断信号将其唤醒,从而进入下一轮循环。到达条件1处,符合条件,减少工作线程数量,并返回null,由外层结束这条线程。这里的decrementWorkerCount()是自旋式的,一定会减1
+
+2. Running 状态,任务还没有完全执行完
+
+```java
+Runnable r = timed ?
+    // 内部的方法
+    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
+    workQueue.take();
+```
+
+```java
+    public E take() throws InterruptedException {
+        E x;
+        int c = -1;
+        final AtomicInteger count = this.count;
+        final ReentrantLock takeLock = this.takeLock;
+        // 中断获取锁
+        takeLock.lockInterruptibly();
+        try {
+            while (count.get() == 0) {
+                notEmpty.await();
+            }
+            x = dequeue();
+            c = count.getAndDecrement();
+            if (c > 1)
+                notEmpty.signal();
+        } finally {
+            takeLock.unlock();
+        }
+        if (c == capacity)
+            signalNotFull();
+        return x;
+    }
+
+    public void lockInterruptibly() throws InterruptedException {
+        sync.acquireInterruptibly(1);
+    }
+
+    public final void acquireInterruptibly(int arg)
+            throws InterruptedException {
+        // 重置中断状态
+        if (Thread.interrupted())
+            throw new InterruptedException();
+        if (!tryAcquire(arg))
+            doAcquireInterruptibly(arg);
+    }
+```

+ 66 - 0
算法/排序/数字出现次数.md

@@ -0,0 +1,66 @@
+## 统计数组中不同元素出现的次数(时间复杂度O(n),空间复杂度o(1))
+
+常规思路是利用map进行统计,但不满足时间和空间复杂度的要求;
+正确思路:
+遍历数组,通过当前元素的值a作为下标,找到下一个元素。最后得到的数组中,下标(因为数组的下标都是从0开始的,所以需要+1)为数组中出现的元素,每个下标对应的值取反输出即是该元素出现的次数。
+
+若当前元素a小于0,则跳过;
+若当前元素a大于0,则判断其作为下标对应的元素b是否大于0。
+若b大于0,则把b的值赋值给a,并把b置为-1;
+若b小于0,则把a置为0,并把b自减1;
+注意遍历时,若当前元素为正数依旧处理该当前元素;
+
+```cpp
+// 举例
+vector<int> arr = {2, 5, 5, 2, 3};
+下标都+1;
+/*
+1、遍历数组,第一个arr[1]=2,然后看下标为2的元素是arr[2]=5。
+2、把arr[2]对应的5赋值给arr[1],然后arr[2]就设置为-1
+3、然后重复整个过程直到结束
+它的整个变化过程就是这样
+- {2, 5, 5, 2, 3}
+- 5, [-1], 5, 2, 3
+- 3, [-1], 5, 2, [-1]
+- 5, [-1], [-1], 2, [-1]
+- [0], [-1], [-1], 2, [-2]
+- [0], [-2], [-1], [0], [-2]
+这个结果表示:1有0个,2有2个,3有一个,4有0个,5有2个
+*/
+```
+
+```cpp
+#include <bits/stdc++.h>
+
+using namespace std;
+
+void sort(vector<int>& nums) {
+    int i = 0;
+    int n = (int) nums.size();
+    while (i < n) {
+        int temp = nums[i] - 1;
+        if (temp < 0) {
+            i++;
+            continue;
+        }
+        if (nums[temp] > 0) {
+            nums[i] = nums[temp];
+            nums[temp] = -1;
+        } else {
+            nums[temp]--;
+            nums[i] = 0;
+        }
+    }
+}
+
+int main() {
+    vector<int> nums{2, 5, 5, 2, 3};
+    sort(nums);
+    for (int i = 0; i < nums.size(); i++) {
+        if (nums[i] < 0)
+            cout << i + 1 << " " << (-nums[i]) << endl;
+    }
+    return 0;
+}
+```
+

BIN
算法/排序算法/assets/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMTUyMDUy,size_16,color_FFFFFF,t_70.png


+ 51 - 1
算法/排序算法/基本排序算法.md

@@ -1,4 +1,6 @@
-## 归并排序
+![在这里插入图片描述](assets/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMTUyMDUy,size_16,color_FFFFFF,t_70.png)
+
+# 归并排序
 
 ```cpp
 #include <bits/stdc++.h>
@@ -82,3 +84,51 @@ int main() {
 }
 ```
 
+# 堆排序
+
+```cpp
+#include <bits/stdc++.h>
+
+using namespace std;
+
+void adjust(vector<int>& nums, int start, int end) {
+    int tmp = nums[start];
+    for (int i = 2 * start + 1; i <= end; i = i * 2 + 1) {
+        // 有右孩子并且左孩子小于右孩子
+        if (i < end && nums[i] < nums[i + 1]) {
+            i++;
+        }
+        // i一定是左右孩子的最大值
+        if (nums[i] > tmp) {
+            nums[start] = nums[i];
+            start = i;
+        } else {
+            // 比左右孩子都大
+            break;
+        }
+    }
+    nums[start] = tmp;
+}
+
+void heapSort(vector<int>& nums) {
+    int len = (int) nums.size();
+    // 第一次建立大根堆,从后往前依次调整
+    for (int i = (len - 1 - 1) / 2; i >= 0; i--) {
+        adjust(nums, i, len - 1);
+    }
+    // 每次将根和待排序的最后一次交换,然后在调整
+    int tmp;
+    for (int i = 0; i < len - 1; i++) {
+        swap(nums[0], nums[len - i - 1]);
+        adjust(nums, 0, len - 1 - i - 1);
+    }
+}
+
+int main() {
+    vector<int> nums = {9, 5, 6, 3, 5, 3, 1, 0, 96, 66};
+    heapSort(nums);
+    for (auto num: nums) cout << num << " ";
+    return 0;
+}
+```
+

+ 3 - 0
算法/贪心/求数组中比左边元素都大同时比右边元素都小的元素.md

@@ -0,0 +1,3 @@
+## 求数组中比左边元素都大同时比右边元素都小的元素,返回这些元素的索引。要求复杂度O(N)
+
+对于每个元素,如果它比左侧最大的值要大,同时比右侧最小的值要小,就满足条件。用两个数组维护,left_max[i] 表示原数组 [0, i) 的最大值,right_min[i] 表示原数组 (i, n) 的最小值。

+ 4 - 0
算法平台/改进.md

@@ -0,0 +1,4 @@
+1. 数据集,目前只有csv文件可以输入,改进为支持图片,视频,文本。类型文件,并且可以在线打标签。
+2. 使用步骤不直观,过于复杂。
+3. 没有用户引导,用户不知道如何使用。
+4. 和中煤系统耦合过高,菜单需要调整修改。

BIN
论文/assets/image-20230816145833671.png


BIN
论文/assets/image-20230816145844068.png


BIN
论文/assets/image-20230816145853300.png


BIN
论文/assets/image-20230816153747750.png


+ 11 - 0
论文/petri网.md

@@ -0,0 +1,11 @@
+![image-20230816145833671](assets/image-20230816145833671.png)
+
+![image-20230816145844068](assets/image-20230816145844068.png)
+
+![image-20230816145853300](assets/image-20230816145853300.png)
+
+单纯网:没有自旋
+
+简单网:没有环
+
+![image-20230816153747750](assets/image-20230816153747750.png)

+ 13 - 0
面经/2023年暑期实习/字节一面.md

@@ -0,0 +1,13 @@
+## 一面
+
+1. tcp三次握手四次挥手
+1. 为什么三次握手,不是两次
+2. kafka为什么这么快
+3. 什么是零拷贝
+4. 进程和线程的区别
+5. 进程和线程的上下文切换
+6. mysql事务隔离级别
+7. mysql事务隔离级别的实现
+8. InnoDB 与 myisam的区别
+8. mysql低层为什么用B+树
+8. 为什么用B树不用二叉树

+ 20 - 0
面经/2023年暑期实习/快手.md

@@ -0,0 +1,20 @@
+## 一面
+
+* 垃圾收集器G1,说说G1的特点
+* mysql隔离级别
+* 如何实现这些隔离级别
+* 如何添加索引
+* 如何排查一个慢SQL
+* mysql为什么用B+树
+* mysql行锁
+* 线程池
+* 线程池如何创建线程--这里回答源码部分
+* 线程池的future--get导致死锁
+* redis为什么快?
+* AOF,RDB底层原理
+* 什么是epoll
+* redis线程模型
+* 进程切换
+* 进程调度算法知道那些?
+
+算法:全排列二和硬币找零

+ 6 - 0
面经/2023年暑期实习/百度.md

@@ -0,0 +1,6 @@
+1. object类有什么方法,finalilze会释放资源吗
+2. volitel关键字
+3. 线程同步方式
+4. springboot注解
+5. spring生命周期
+6. autowired单例

+ 23 - 7
面经/工作/秋招.md

@@ -1,8 +1,24 @@
-| 公司     | 网站                                                    | 投递时间 | 进度 |
-| -------- | ------------------------------------------------------- | -------- | ---- |
-| 百度     | https://talent.baidu.com/jobs/center                    | 7月10号  | 初筛 |
-| 科大讯飞 | https://campus.iflytek.com/official-pc/delivery         | 7月6号   | 初筛 |
-| oppo     | https://careers.oppo.com/university/oppo/center/history | 7月3号   | 初筛 |
-| 米哈游   | https://campus.mihoyo.com/#/campus/applyRecord          | 7月5号   | 初筛 |
-| 大疆     | https://we.dji.com/zh-CN/user                           | 7月7号   | 初筛 |
+| 公司         | 网站                                                         | 投递时间 | 进度 |
+| ------------ | ------------------------------------------------------------ | -------- | ---- |
+| 百度         | https://talent.baidu.com/jobs/center                         | 7月10号  | 初筛 |
+| 科大讯飞     | https://campus.iflytek.com/official-pc/delivery              | 7月6号   | 初筛 |
+| oppo         | https://careers.oppo.com/university/oppo/center/history      | 7月3号   | 初筛 |
+| 米哈游       | https://campus.mihoyo.com/#/campus/applyRecord               | 7月5号   | 初筛 |
+| 大疆         | https://we.dji.com/zh-CN/user                                | 7月7号   | 初筛 |
+| 小红书       | https://job.xiaohongshu.com/record/campus                    | 7月17号  | 笔试 |
+| 联想         | https://talent.lenovo.com.cn/account/apply                   | 7月17号  | 初筛 |
+| 字节         | https://jobs.bytedance.com/campus/position/application       | 7月17号  | 一面 |
+| 三一重工     | https://sanycampus.m.zhiye.com/#/jobs?code=def8ad56-4f17-48e0-a3bb-d85f9983ca96 | 7月17号  | 初筛 |
+| 长鑫存储     | http://jobs.cxmt.com/Campus                                  | 7月17号  | 初筛 |
+| 网易         | https://campus.163.com/app/personal/apply                    | 7月17号  | 初筛 |
+| 数禾         | https://shuhegroup1.zhiye.com/personal/deliveryRecord        | 7月17号  | 初筛 |
+| 搜狐         | https://app.mokahr.com/campus_apply/cyou-inc/42233?recommendCode=DSJ9ZJhr#/jobs | 7月17号  | 初筛 |
+| 远景科技集团 | https://app.mokahr.com/campus-recruitment/envisiongroup/43123?type=school#/candidateHome/applications | 7月20号  | 初筛 |
+| 多益         | https://xz.duoyi.com/v40/#/positions                         | 7月20号  | 初筛 |
+| 地平线       | https://wecruit.hotjob.cn/SU62d915040dcad43c775ec12c/mc/position/campus?acotycoCode=gmscfw&recruitType=1 | 7月20号  | 初筛 |
+| 三禾信安     | https://sansec.zhiye.com/campus/detail?jobAdId=db7e79ba-6ae2-476f-b411-a1a3164a2da7 | 7月27号  | 初筛 |
+| 海柔创新     | https://hairobotics.zhiye.com/campus/detail?jobAdId=a67a3fce-7c13-43ad-b997-2dad7a33ea51 | 7月27号  | 初筛 |
+| 滴滴         | https://app.mokahr.com/campus_apply/didiglobal/96064?recommendCode=DSu3BRUr#/candidateHome/applications | 7月27号  | 初筛 |
+| 作业帮       | https://app.mokahr.com/campus-recruitment/zuoyebang/39595#/jobs | 7月27号  | 初筛 |
+| 快手         | https://campus.kuaishou.cn/#/campus/resume                   | 7月27号  | 初筛 |
 

+ 64 - 1
面经/问答/JVM.md

@@ -20,12 +20,55 @@ Minor GC 通常在新生代中的 Eden 区域满时,或者 Survivor 区域中
 - **Major GC 是清理老年代。**
 - **Full GC 是清理整个堆空间—包括年轻代和老年代。**
 
+## 频繁发生GC如何优化
+
+`jstat -gcutil 5280 1000` 命令是用于监视 Java 虚拟机的垃圾回收统计信息的命令。这个命令通常在命令行中执行,用于实时监测 Java 应用程序的内存管理和垃圾回收情况。
+
+解释一下命令的各个部分:
+
+- `jstat`: Java 虚拟机统计信息工具,用于监测虚拟机状态和性能数据。
+- `-gcutil`: 表示查询垃圾回收的统计信息,包括各个垃圾回收器的使用情况。
+- `5280`: 进程的进程 ID 或虚拟机标识符(JVM ID),用于指定要监控的 Java 虚拟机实例。这个值需要根据实际情况进行替换。
+- `1000`: 表示每隔 1000 毫秒(1秒)收集一次统计信息并输出。
+
+### 可能原因
+
+* 内存泄漏(代码有问题,对象引用没及时释放,导致对象不能及时回收)。
+* 死循环。在死循环中,对象不断被创建,但无法被正常释放,最终导致堆内存耗尽,触发 Full GC 进行垃圾回收。
+* 大对象。 尤其是大对象,80%以上的情况就是他。 那么大对象从哪里来的呢?
+* 数据库(包括MySQL和MongoDB等NoSQL数据库),结果集太大。
+* 第三方接口传输的大对象。
+* 消息队列,消息太大。
+
+## JVM调优
+
+对应的参数列表
+
+```shell
+-XX:+PrintGC 输出GC日志
+-XX:+PrintGCDetails 输出GC的详细日志
+-XX:+PrintGCTimeStamps 输出GC的时间戳(以基准时间的形式)
+-XX:+PrintGCDateStamps 输出GC的时间戳(以日期的形式,如 2013-05-04T21:53:59.234+0800)
+-XX:+PrintHeapAtGC 在进行GC的前后打印出堆的信息
+-Xloggc:../logs/gc.log 日志文件的输出路径
+```
+
+当元空间出现内存碎片化时,我们会着重关注是不是创建了大量的类加载器。
+
+通过进一步分析,发现是由于反射导致创建大量 DelegatingClassLoader。其核心原理如下:
+
+在 JVM 上,最初是通过 JNI 调用来实现方法的反射调用,当 JVM 注意到通过反射经常访问某个方法时,它将生成字节码来执行相同的操作,称为膨胀(inflation)机制。如果使用字节码的方式,则会为该方法生成一个 DelegatingClassLoader,如果存在大量方法经常反射调用,则会导致创建大量 DelegatingClassLoader。
+
 ## JVM调优
 
 -Xmx –Xms:指定 java 堆最大值(默认值是物理内存的 1/4(<1GB))和初始 java 堆最小值(默认值是物理内存的 1/64(<1GB))
 
 开发过程中,通常会将 -Xms 与 -Xmx 两个参数配置成相同的值,其目的是为了能够在 java 垃圾回收机制清理完堆区后不需要重新分隔计算堆区的大小而浪费资源。
 
+
+
+创建大量MAP导致内存暴涨,优化kafka消息
+
 ## CMS垃圾收集器
 
 CMS(标记并发清除垃圾收集器),对比以前的jvm垃圾收集器,最大区别在于并发,当GC线程工作的时候,用户线程不会完全停止,会与GC线程并发执行
@@ -39,7 +82,7 @@ CMS主要目的为了避免老年代GC出现长时间的卡顿,主要步骤可
 
 CMS垃圾收集器的缺点
 
-* 产生大量空间碎片:因为老年代是标记-清算法,所以会产生大量的空间碎片
+* 产生大量空间碎片:因为老年代是标记-清算法,所以会产生大量的空间碎片
 * 对CPU资源敏感:应该它与用户线程并行, 所以会导致系统资源被占用
 * 内存需要预留:CMS垃圾收集器可以一边回收垃圾,一边处理用户线程,那需要在这个过程中保证有充足的内存空间供用户使用。如果CMS运行过程中预留的空间不够用,会报错
 
@@ -146,3 +189,23 @@ jvm内存区域大体上可以分为线程私有和线程共有两大部分
 
 
 
+## 内存泄漏和内存溢出的区别
+
+在Java中,内存泄漏(Memory Leak)和内存溢出(Memory Overflow)是两个不同的概念,它们有一些区别。
+
+1. 内存泄漏(Memory Leak): 内存泄漏指的是在程序运行过程中,由于错误的内存管理导致无法再被使用的对象仍然占据着内存空间,而这些占用的内存无法被释放。这意味着系统的可用内存逐渐减少,直到最终导致内存耗尽。常见的内存泄漏场景包括:
+   - 未正确释放动态分配的内存:如果程序在分配了内存后没有及时释放,这些内存就会一直占据系统资源。
+   - 对象引用仍存在但不再需要:如果某个对象的引用仍然存在,即使该对象不再需要,垃圾回收器也无法回收该对象所占用的内存。
+2. 内存溢出(Memory Overflow): 内存溢出指的是程序在申请内存时,无法获得足够的内存空间以满足其需求,导致无法继续执行程序或者出现异常。当程序需要分配更多内存而可用内存不足时,就会发生内存溢出。常见的内存溢出场景包括:
+   - 堆内存溢出:当创建过多的对象并且无法被垃圾回收时,堆内存可能会耗尽。这通常是由于程序中存在内存泄漏或者申请了过大的对象导致的。
+   - 栈内存溢出:当递归调用层级过深、方法调用过多或者栈帧过大时,栈内存可能会耗尽。每个方法调用都会在栈上创建一个栈帧,如果栈帧数量超过了栈的容量,就会导致栈内存溢出。
+
+区别:
+
+- 内存泄漏是指无法释放已经分配的内存,导致内存持续占用和耗尽;而内存溢出则是指无法获得足够的内存空间来满足需求,导致程序无法执行或者出现异常。
+- 内存泄漏通常是逐渐发生的,随着时间的推移导致内存占用不断增加;而内存溢出通常是在程序执行过程中突然发生的,因为需要的内存超过了可用内存。
+- 内存泄漏是程序中的错误行为,通常是由于忘记释放资源或者引用未及时清理等原因导致的;而内存溢出可能是因为程序设计问题,如递归调用或者对象太大等。
+
+## 内存泄漏
+
+hbase配置类需要成为static

+ 215 - 0
面经/问答/K8S.md

@@ -0,0 +1,215 @@
+## 什么是K8S
+
+Kubernetes 是一个可移植的、可扩展的开源平台,用于管理容器化的工作负载和服务,可促进声明式配置和自动化。 Kubernetes 拥有一个庞大且快速增长的生态系统。Kubernetes 的服务、支持和工具广泛可用。
+
+![image-20230905160248241](assets/image-20230905160248241.png)
+
+## pod
+
+容器的本质是进程,Kubernetes就是操作系统。
+
+在一个OS当中,进程并非独自运行的,而是以进程组的方式,有原则的组织在一起。
+
+Kubernetes当中,将“进程组”的概念映射到了容器技术中。
+
+为什么需要这个“组”的概念??
+
+应用之间往往具有密切的协作关系,类似于“进程和进程组”。
+
+关于如何妥善处理成组调度的问题?
+
+* Mesos有一个资源囤积(resource hoarding)机制,当所有设置了Affinity约束的任务都到达之后,才开始对他们进行统一调度
+* Google Omega论文,提出乐观调度处理冲突的方法,即:先不管这些冲突,而是通过回滚机制在出现冲突后解决问题
+
+Kubernetes中得到了妥善解决,调度器**统一按照Pod而非容器的资源需求进行计算**。
+
+但是如果仅仅这样,那么Kubernetes可以在调度器层面解决 容器应用之间的紧密关系,而不一定要把Pod设置为最基本单位?
+
+引出Pod在Kubernetes项目中更加重要的意义,即:**容器设计模式**。
+
+* **Pod只是一个逻辑概念,Kubernetes真正处理的,还是宿主机OS上的Namespace和Cgroups,物理上并没有存在一个所谓的Pod的边界或者隔离环境。**
+
+* Pod,是一组共享了某些资源的容器。
+
+* **Pod当中所有的容器,共享的是同一个Network Namespace,并且可以声明共享同一个Volume。**
+
+**在Pod当中,容器是对等的关系**,而如果是用简单用docker run共享,则必然会有容器先启动,进而产生拓扑关系。
+
+### **Infra容器**(新版本叫Init容器)
+
+为了实现这样的对等关系,Pod的实现需要一个中间容器,叫做`Infra`容器。
+
+**它永远是首先被创建的容器,其他用户定义的容器通过Join Network Namespace方式,与Infra关联起来。**
+
+Infra容器一定要占据非常少的资源,所以它使用一个非常特殊的image,叫**`k8s.gcr.io/pause`**,(称为**pause 镜像**)它是用汇编语言编写、永远处于暂停状态,解压后也只有100~200KB左右。
+
+Pod 的生命周期和 Infra 容器一致,而与其中的用户定义容器无关。
+
+![image-20230905161245730](assets/image-20230905161245730.png)
+
+要为Kubernetes开发一个网络插件时,应该**重点考虑如何配置这个Pod的Network Namespace,而不是每一个用户容器如何使用你的网络配置**。
+
+对于**共享Volume**而言,只需要**把Volume的定义设计在Pod层级**即可:**一个 Volume 对应的宿主机目录对于 Pod 来说就只有一个**,Pod 里的容器只要声明挂载这个 Volume,就一定可以共享这个 Volume 对应的宿主机目录。
+
+## pod配置文件config
+
+**特殊的Projected Volume**
+
+它们存在的意义不是为了存放容器里的数据,也不是用来进行容器和宿主机之间的数据交换。这些特殊 Volume 的作用,**是为容器提供预先定义好的数据。**
+
+一共支持四种Volume:
+
+1. Secret: 保密数据
+
+把 Pod 想要访问的加密数据,存放到 Etcd 中。然后,就可以通过在 Pod 的容器里挂载 Volume 的方式,访问到这些 Secret 里保存的信息。
+
+经典场景:存放数据库的Credential信息:
+
+2. ConfigMap: 配置文件
+
+ConfigMap 保存的是不需要加密的、应用所需的配置信息,其他用法与Secret相同。
+
+用ConfigMap来保存一个java应用的配置文件ui.properties:
+
+3. Downward API:  Pod元数据
+
+让 Pod 里的容器能够直接获取到这个 Pod API 对象本身的信息。
+
+4. ServiceAccountToken: 服务账户,通过验证
+
+> **疑问:现在有了一个 Pod,我能不能在这个 Pod 里安装一个 Kubernetes 的 Client,这样就可以从容器里直接访问并且操作这个 Kubernetes 的 API 了呢?**
+>
+> **答案是:可以,但是需要解决API Server的授权问题。**
+
+`Service Account` 对象的作用,就是 Kubernetes 系统内置的一种“服务账户”,它是 **Kubernetes 进行权限分配的对象。**
+
+ Service Account 的授权信息和文件,实际上**保存在它所绑定的一个特殊的 Secret 对象里的**。这个特殊的 Secret 对象,就叫作**ServiceAccountToken**。
+
+**任何运行在 Kubernetes 集群上的应用,都必须使用这个 ServiceAccountToken 里保存的授权信息,也就是 Token,才可以合法地访问 API Server**。
+
+Kubernetes为了方便使用,为用户提供一个默认的服务账户(default Service Account),任何一个运行在 Kubernetes 里的 Pod,都可以直接使用这个默认的 Service Account,而无需显示地声明挂载它。
+
+## Replicaset
+
+`ReplicaSet`是kubernetes中的一种副本控制器,简称`rs`,主要作用是控制由其管理的pod,使pod副本的数量始终维持在预设的个数。它的主要作用就是保证一定数量的Pod能够在集群中正常运行,它会持续监听这些Pod的运行状态,在Pod发生故障时重启pod,pod数量减少时重新运行新的 Pod副本。**官方推荐不要直接使用ReplicaSet,用Deployments取而代之**,Deployments是比ReplicaSet更高级的概念,它会管理ReplicaSet并提供很多其它有用的特性,最重要的是Deployments支持声明式更新,声明式更新的好处是不会丢失历史变更。所以Deployment控制器不直接管理Pod对象,而是由 Deployment 管理ReplicaSet,再由ReplicaSet负责管理Pod对象。
+
+
+
+Replicaset核心作用在于用户创建指定数量的pod副本,并确保pod副本一直处于满足用户期望的数量, 起到多退少补的作用,并且还具有自动扩容缩容等制。
+Replicaset控制器主要由三个部分组成:
+1、**用户期望的pod副本数**:用来定义由这个控制器管控的pod副本有几个
+2、**标签选择器**:选定哪些pod是自己管理的,如果通过标签选择器选到的pod副本数量少于我们指定的数量,需要用到下面的组件
+3、**pod资源模板**:如果集群中现存的pod数量不够我们定义的副本中期望的数量怎么办,需要新建pod,这就需要pod模板,新建的pod是基于模板来创建的。
+
+## Deployment
+
+为了更好地解决服务编排的问题,k8s在V1.2版本开始,引入了deployment控制器,值得一提的是,这种控制器并不直接管理pod,
+
+而是通过管理replicaset来间接管理pod,即:deployment管理replicaset,replicaset管理pod。所以deployment比replicaset的功能更强大。
+
+![image-20230905164914619](assets/image-20230905164914619.png)
+
+deployment的主要功能有下面几个:
+
+- 支持replicaset的所有功能
+- 支持发布的停止、继续
+- 支持版本的滚动更新和版本回退
+
+## StatefulSet
+
+作为一个后端工程师,因为负责的大部分项目都是`Web`服务这类的“无状态应用”,在平时工作中接触到的最常用的`Kubernetes`控制器是`Deployment`,但是`Deployment`只适合于编排“无状态应用”,它会假设一个应用的所有 `Pod`是完全一样的,互相之间也没有顺序依赖,也无所谓运行在哪台宿主机上。正因为每个`Pod`都一样,在需要的时候可以水平扩/缩,增加和删除`Pod`。
+
+但是并不是所有应用都是无状态的,尤其是每个实例之间有主从关系的应用和数据存储类应用,针对这类应用使用`Deployment`控制器无法实现正确调度,所以`Kubernetes`里采用了另外一个控制器`StatefulSet`负责调度有状态应用的`Pod`,保持应用的当前状态始终等于应用定义的所需状态。
+
+## node affinity
+
+pod绑定节点最简单的方法是使用 nodeSelector,但它比较简单粗暴,使用起来不能灵活调度,这个在后续版本中也会慢慢过时,所以我们一般用 nodeAffinity来实现这些需求。
+
+Node Affinity
+ Affinity 翻译成中文是“亲和性”,它对应的是 Anti-Affinity,我们翻译成“互斥”。这两个词比较形象,可以把 pod 选择 node 的过程类比成磁铁的吸引和互斥,不同的是除了简单的正负极之外,pod 和 node 的吸引和互斥是可以灵活配置的。
+
+Affinity的优点:
+
+匹配有更多的逻辑组合,不只是字符串的完全相等
+ 调度分成软策略(soft)和硬策略(hard),在软策略下,如果没有满足调度条件的节点,pod会忽略这条规则,继续完成调度。
+ 目前主要的node affinity:
+
+requiredDuringSchedulingIgnoredDuringExecution
+ 表示pod必须部署到满足条件的节点上,如果没有满足条件的节点,就不停重试。其中IgnoreDuringExecution表示pod部署之后运行的时候,如果节点标签发生了变化,不再满足pod指定的条件,pod也会继续运行。
+
+requiredDuringSchedulingRequiredDuringExecution
+ 表示pod必须部署到满足条件的节点上,如果没有满足条件的节点,就不停重试。其中RequiredDuringExecution表示pod部署之后运行的时候,如果节点标签发生了变化,不再满足pod指定的条件,则重新选择符合要求的节点。
+
+preferredDuringSchedulingIgnoredDuringExecution
+ 表示优先部署到满足条件的节点上,如果没有满足条件的节点,就忽略这些条件,按照正常逻辑部署。
+
+preferredDuringSchedulingRequiredDuringExecution
+ 表示优先部署到满足条件的节点上,如果没有满足条件的节点,就忽略这些条件,按照正常逻辑部署。其中RequiredDuringExecution表示如果后面节点标签发生了变化,满足了条件,则重新调度到满足条件的节点。
+
+## Toleration
+
+节点亲和性 是 Pod的一种属性,它使 Pod 被吸引到一类特定的节点(这可能出于一种偏好,也可能是硬性要求)。 **污点(Taint)** 则相反——它使节点能够排斥一类特定的 Pod。
+
+**容忍度(Toleration)** 是应用于 Pod 上的。容忍度允许调度器调度带有对应污点的 Pod。 容忍度允许调度但并不保证调度:作为其功能的一部分, 调度器也会评估其他参数。
+
+污点和容忍度(Toleration)相互配合,可以用来避免 Pod 被分配到不合适的节点上。 每个节点上都可以应用一个或多个污点,这表示对于那些不能容忍这些污点的 Pod, 是不会被该节点接受的。
+
+## service
+
+Service是一种抽象的对象,它定义了一组Pod的逻辑集合和一个用于访问它们的策略,一个Serivce下面包含的Pod集合一般是由**Label Selector**来决定的。假如我们后端运行了3个副本,这些副本都是可以替代的,因为前端并不关心它们使用的是哪一个后端服务。尽管由于各种原因后端的Pod集合会发生变化,但是前端却不需要知道这些变化,也不需要自己用一个列表来记录这些后端的服务,Service的这种抽象就可以帮我们达到这种解耦的目的。
+
+
+
+> Node IP:Node节点的IP地址
+>  Pod IP:Pod的IP地址
+>  Cluster IP:Service的IP地址
+
+首先,Node IP是Kubernetes集群中节点的物理网卡IP地址(一般为内网),所有属于这个网络的服务器之间都可以直接通信,所以Kubernetes集群外要想访问Kubernetes集群内部的某个节点或者服务,肯定得通过Node IP进行通信(这个时候一般是通过外网IP了)
+
+然后Pod IP是每个Pod的IP地址,它是Docker Engine根据docker0网桥的IP地址段进行分配的(我们这里使用的是flannel这种网络插件保证所有节点的Pod IP不会冲突)
+
+最后Cluster IP是一个虚拟的IP,仅仅作用于Kubernetes Service这个对象,由Kubernetes自己来进行管理和分配地址,当然我们也**无法ping这个地址**,他没有一个真正的实体对象来响应,他只能结合Service Port来组成一个可以通信的服务。
+
+![在这里插入图片描述](assets/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzIxMTg3NTE1,size_16,color_FFFFFF,t_70.png)
+
+## Ingress
+
+ingress翻译过来是入口的意思,k8s希望ingress是整个集群流量的入口,引入ingress后整个请求如下图所示
+
+![image.png](assets/c8054fbec1b14607b2759ea0d1ddc2f4tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp)
+
+### 为什么需要Ingress资源
+
+由于K8S集群拥有强大的副本控制能力,Pod随时可能从一个节点上被驱逐到另一个节点上,或者直接销毁再来一个新的。
+
+然而伴随着Pod的销毁和重生,Pod的IP等信息不断地在改变,此时使用K8S提供的Service机制可以解决这一问题,Service通过标签选定指定的Pod作为后端服务,并监听这些Pod的变化。
+
+在对外暴露服务时,使用Service的NodePort是一个方法,但还会有以下几个问题
+
+### 问题1 - 如何管理端口
+
+当需要对外暴露的服务量比较多的时候,端口管理的问题便会暴露出来。并且service只支持4层代理,也就是只能根据ip+端口
+
+此时的一个处理方案是使用一个代理服务(例如Nginx)根据请求信息将请求转发到不同的服务上去。
+
+### 问题2 - 如何管理转发配置
+
+每当有新服务加入,都需要对该服务的配置进行修改、升级,在服务数量逐渐变多后,该配置项目会变得越来越大,手工修改的风险也会逐渐增高。
+
+那么需要一个工具来简化这一过程,希望可以通过简单的配置动态生成代理中复杂的配置,最好还可以顺手重新加载配置文件。
+
+K8S刚好也提供了此类型资源。
+
+## 健康检查
+
+健康检查(health check)是用于检测应用实例是否正常工作,对应用状态的监控,保障业务高可用的一种机制。
+
+k8s健康检测主要分为以下三种:
+
+- 存活性探测(Liveness probes) :主要是探测应用是否还活着。如果检测到应用没有存活就杀掉当前pod并重启。
+- 就绪性探测(Readiness probes):只要是探测应用是否准备好接受请求访问,如果检测应用准备好了,就把请求流量放进来;反之,则把应用节点从注册中心拿掉。
+- 启动探测(Startup Probes):对于旧应用需要更长的启动时间,这时候既不想重启应用也不想让请求访问进来,可以设置启动探测给足够的启动时间保证应用启动成功。
+
+![image-20230905203232434](assets/image-20230905203232434.png)
+
+> **二者不能相互替代,根据实际情况,配合使用。只配置了readiness是无法触发容器重启的;只配置了liveness,可能应用还没准备好,导致请求失败,status是running,Ready是0/1。**

+ 509 - 5
面经/问答/Mysql.md

@@ -11,8 +11,7 @@
 2. 优化 SQL 语句:优化 SQL 语句可以通过多种方式实现,例如避免使用通配符查询,优化复杂查询语句,避免不必要的连接查询和子查询,合理使用聚合函数和 GROUP BY 子句等。可以通过使用数据库性能分析工具(如 MySQL 自带的慢查询日志)来定位慢查询,并对其进行优化。
 3. 缓存和缓冲技术:通过使用缓存和缓冲技术可以减轻数据库的负载,提高查询性能。可以使用数据库自带的查询缓存功能,或者使用外部缓存技术如 Redis、Memcached 等进行数据缓存,减少对数据库的频繁查询。
 4. 合理配置数据库参数:MySQL 有丰富的配置参数可以进行调优,例如调整缓冲池大小、设置合理的连接数、开启合适的日志等,可以根据实际需求和硬件资源来配置数据库参数,以达到最佳性能。
-5. 定期维护数据库:数据库的性能和稳定性需要定期进行维护,包括定期清理无用的数据和索引,进行数据库备份和日志管理,定期更新统计信息等。定期维护可以保持数据库的健康状态,提升查询性能。
-6. 可以考虑使用分库分表技术,例如对于用户中奖详情单我选择了分库分表,因为有多个用户和不同活动同时竞争这个表,数据库访问压力比较大,所以就要选择分库分表
+6. 可以考虑使用分库分表技术
 
 ## mysql底层数据结构
 
@@ -42,14 +41,23 @@
 
 3. InnoDB 存储引擎:InnoDB 是 MySQL 的一种常用存储引擎,它使用了多版本并发控制(MVCC)和行级锁来实现高并发性和事务支持。InnoDB 存储引擎的核心数据结构包括页(page)、记录(record)、索引(index)和事务日志(transaction log)等。
 
+## nysql低层文件结构
+
+- db.opt,用来存储当前数据库的默认字符集和字符校验规则。
+- t_order.frm ,t_order 的**表结构**会保存在这个文件。在 MySQL 中建立一张表都会生成一个.frm 文件,该文件是用来保存每个表的元数据信息的,主要包含表结构定义。
+- t_order.ibd,t_order 的**表数据**会保存在这个文件。表数据既可以存在共享表空间文件(文件名:ibdata1)里,也可以存放在独占表空间文件(文件名:表名字.ibd)。这个行为是由参数 innodb_file_per_table 控制的,若设置了参数 innodb_file_per_table 为 1,则会将存储的数据、索引等信息单独存储在一个独占表空间,从 MySQL 5.6.6 版本开始,它的默认值就是 1 了,因此从这个版本之后, MySQL 中每一张表的数据都存放在一个独立的 .ibd 文件。
+
 ## 联合索引定义要注意哪些点
 
 在 MySQL 中定义联合索引时,需要注意以下几点:
 
 1. 列顺序:联合索引中的列顺序非常重要,它会影响索引的效果。通常情况下,应该将被频繁用于查询的列放在联合索引的前面,这样可以使索引在查询时更加有效。例如,如果查询中经常同时使用列 A 和列 B 进行查询,那么联合索引应该按照 (A, B) 的顺序定义,而不是 (B, A)。
+
 2. 列选择:不要将过多的列包含在联合索引中,因为索引的大小对数据库性能有影响。过大的索引可能会导致磁盘 I/O 操作增加,并且会占用额外的存储空间,导致性能下降
-3. 索引选择:不是所有的列都适合联合索引。联合索引在使用时会按照索引列的顺序进行匹配,因此只有查询中包含了索引的前缀列时,索引才能被充分利用。因此,应该选择那些在查询中经常一起使用的列进行联合索引定义。
-4. 更新性能:联合索引在更新操作时可能会导致性能下降。因为联合索引涉及多个列,更新其中的一个列可能需要更新整个索引。因此,在定义联合索引时应该考虑更新性能的影响,避免频繁的更新操作导致性能下降。
+
+   * 索引选择:不是所有的列都适合联合索引。联合索引在使用时会按照索引列的顺序进行匹配,因此只有查询中包含了索引的前缀列时,索引才能被充分利用。因此,应该选择那些在查询中经常一起使用的列进行联合索引定义。
+
+   * 更新性能:联合索引在更新操作时可能会导致性能下降。因为联合索引涉及多个列,更新其中的一个列可能需要更新整个索引。因此,在定义联合索引时应该考虑更新性能的影响,避免频繁的更新操作导致性能下降。
 
 ## 数据库ACID
 
@@ -71,9 +79,16 @@ InnoDB 引擎通过什么技术来保证事务的这四个特性的呢?
 
 1. 读未提交 (Read Uncommitted):最低的隔离级别,事务可以读取到其他事务未提交的数据。这种隔离级别可能导致脏读(Dirty Read),即读取到其他事务未提交的数据,可能会引起数据的不一致性。
 2. 读提交 (Read Committed):事务只能读取到其他事务已经提交的数据,保证了数据的一致性。但在该隔离级别下,可能会出现不可重复读(Non-repeatable Read)问题,即在同一事务内多次读取同一行数据时,可能会得到不同的结果。
-3. 可重复读 (Repeatable Read):事务在执行期间对同一行数据进行读取时,会保持一致的结果。其他事务对该行数据的修改只有在当前事务提交后才能生效。这种隔离级别可以避免不可重复读问题,但仍然可能出现幻读(Phantom Read)问题,即在同一事务内多次执行相同的查询时,可能会得到不同的结果。
+3. 可重复读 (Repeatable Read):事务在执行期间对同一行数据进行读取时,会保持一致的结果。其他事务对该行数据的修改只有在当前事务提交后才能生效。这种隔离级别可以避免不可重复读问题,但仍然可能出现幻读(Phantom Read)问题,即在同一事务内多次执行相同的查询时,可能会得到不同的结果。(事务B插入一个数据,事务A进行更新,然后A事务就会读取到这个新插入的数据)
 4. 串行化 (Serializable):最高的隔离级别,事务会对数据库中的数据加锁,防止其他事务对数据的并发访问。这种隔离级别可以避免幻读问题,但可能会导致性能下降,因为事务需要等待其他事务释放锁。
 
+## 数据库隔离级别如何实现
+
+* 读未提交:因为可以读到未提交事务修改的数据,所以直接读取最新的数据就好了;
+* 读提交:通过 **Read View 来实现的**,**「读提交」隔离级别是在「每个语句执行前」都会重新生成一个 Read View**
+* 可重复读:通过 **Read View 来实现的**,**「可重复读」隔离级别是「启动事务时」生成一个 Read View,然后整个事务期间都在用这个 Read View**。
+* 串行化:通过加读写锁的方式来避免并行访问;
+
 ## 数据库MVCC
 
 MVCC(Multi-Version Concurrency Control,多版本并发控制)是一种数据库管理系统(DBMS)中的并发控制机制,用于在多用户并发访问数据库时保障事务的隔离性和一致性。MVCC通过在数据库中为每个事务创建多个版本的数据副本,使多个事务可以同时读取和修改数据库中的数据,而不会相互干扰。
@@ -98,3 +113,492 @@ MVCC(Multi-Version Concurrency Control,多版本并发控制)是一种数
 - 按「物理存储」分类:**聚簇索引(主键索引)、二级索引(辅助索引)(非聚簇索引)**。
 - 按「字段特性」分类:**主键索引、唯一索引、普通索引、前缀索引**。
 - 按「字段个数」分类:**单列索引、联合索引**。
+
+## MySQL为什么使用B+树而不是使用B树
+
+- B+ 树的非叶子节点不存放实际的记录数据,仅存放索引,因此数据量相同的情况下,相比存储即存索引又存记录的 B 树,B+树的非叶子节点可以存放更多的索引,因此 B+ 树可以比 B 树更「矮胖」,查询底层节点的磁盘 I/O次数会更少。
+- B+ 树有大量的冗余节点(所有非叶子节点都是冗余索引),这些冗余索引让 B+ 树在插入、删除的效率都更高,比如删除根节点的时候,不会像 B 树那样会发生复杂的树的变化;
+- B+ 树叶子节点之间用链表连接了起来,有利于范围查询,而 B 树要实现范围查询,因此只能通过树的遍历来完成范围查询,这会涉及多个节点的磁盘 I/O 操作,范围查询效率不如 B+ 树。
+
+## MySQL 有哪些锁?
+
+###  表级锁
+
+* 表锁
+* 元数据锁
+* 意向锁
+
+当执行插入、更新、删除操作,需要先对表加上「意向独占锁」,然后对该记录加独占锁。
+
+*  AUTO-INC 锁
+
+### 行级锁
+
+*  Record Lock
+
+**记录锁,锁住单行数据**
+
+*  Gap Lock
+
+**间隙锁之间是兼容的,即两个事务可以同时持有包含共同间隙范围的间隙锁,并不存在互斥关系,因为间隙锁的目的是防止插入幻影记录而提出的**
+
+*  Next-Key Lock
+
+**next-key lock 是包含间隙锁+记录锁的,如果一个事务获取了 X 型的 next-key lock,那么另外一个事务在获取相同范围的 X 型的 next-key lock 时,是会被阻塞的**
+
+* 插入意向锁
+
+一个事务在插入一条记录的时候,需要判断插入位置是否已被其他事务加了间隙锁(next-key lock 也包含间隙锁)。
+
+如果有的话,插入操作就会发生**阻塞**,直到拥有间隙锁的那个事务提交为止(释放间隙锁的时刻),在此期间会生成一个**插入意向锁**,表明有事务想在某个区间插入新记录,但是现在处于等待状态。
+
+## 加锁规则
+
+唯一索引等值查询:
+
+- 当查询的记录是「存在」的,在索引树上定位到这一条记录后,将该记录的索引中的 next-key lock 会**退化成「记录锁」**。
+- 当查询的记录是「不存在」的,在索引树找到第一条大于该查询记录的记录后,将该记录的索引中的 next-key lock 会**退化成「间隙锁」**。
+
+非唯一索引等值查询:
+
+- 当查询的记录「存在」时,由于不是唯一索引,所以肯定存在索引值相同的记录,于是非唯一索引等值查询的过程是一个扫描的过程,直到扫描到第一个不符合条件的二级索引记录就停止扫描,然后**在扫描的过程中,对扫描到的二级索引记录加的是 next-key 锁,而对于第一个不符合条件的二级索引记录,该二级索引的 next-key 锁会退化成间隙锁。同时,在符合查询条件的记录的主键索引上加记录锁**。
+- 当查询的记录「不存在」时,**扫描到第一条不符合条件的二级索引记录,该二级索引的 next-key 锁会退化成间隙锁。因为不存在满足查询条件的记录,所以不会对主键索引加锁**。
+
+非唯一索引和主键索引的范围查询的加锁规则不同之处在于:
+
+- 唯一索引在满足一些条件的时候,索引的 next-key lock 退化为间隙锁或者记录锁。
+- 非唯一索引范围查询,索引的 next-key lock 不会退化为间隙锁和记录锁。
+
+其实理解 MySQL 为什么要这样加锁,主要要以避免幻读角度去分析,这样就很容易理解这些加锁的规则了。
+
+## InnoDB 和 MyISAM 引擎的区别
+
+InnoDB和MyISAM是MySQL数据库中常见的两种存储引擎,它们有一些重要的区别。
+
+1. 事务支持:InnoDB引擎支持事务,可以使用ACID(原子性、一致性、隔离性和持久性)特性来确保数据的完整性和一致性。而MyISAM引擎不支持事务,它的操作是自动提交的,无法回滚。
+2. 锁的等级:InnoDB引擎在高并发读写操作下表现更好。它支持行级锁定,可以同时处理多个并发操作,从而提高了数据库的并发性能。相比之下,MyISAM引擎只支持表级锁定,当某个操作在修改表时,其他操作必须等待,可能导致并发性能下降。
+3. 外键约束:InnoDB引擎通过外键约束来保持数据完整性,可以定义外键关系。而MyISAM引擎不支持外键约束,需要在应用层面来维护数据的完整性。
+4. 崩溃恢复:InnoDB引擎具有崩溃恢复能力,可以保证数据库在崩溃后更好地恢复。MyISAM引擎在崩溃后恢复较差,可能会导致数据丢失或损坏。(因为使用了表级锁,非聚簇索引。而InnoDB使用redo log恢复)
+5. 全文搜索功能:MyISAM引擎支持全文索引和全文搜索功能,可以对文本进行高效的全文搜索。而InnoDB引擎在MySQL 5.6版本之前不支持全文索引,需要借助其他插件或引擎来实现全文搜索。
+5. 索引结构:InnoDB引擎使用聚簇索引(Clustered Index),将数据存储在主键的索引树中,可以提高查询效率。而MyISAM引擎使用非聚簇索引(Non-clustered Index),索引文件和数据文件分开存储。
+
+## 什么是全文索引
+
+使用`like%xxx%`进行模糊查询时,字段的索引就会失效。因此,在数据量大的情况下,通过此种方式查询的效率极低。这个时候,就可通过全文索引(Full-Text Search)来进行优化。
+
+全文索引(Full-Text Search)是将存储于数据库中的整本书或整篇文章中的任意信息查找出来的技术。它可以根据需要获得全文中有关章、节、段、句、词等信息,也可以进行各种统计和分析。
+
+全文索引一般是通过倒排索引实现的,倒排索引如同 B+Tree 一样,也是一种索引结构。它在辅助表中存储了单词与单词自身在一个或多个文档中所在位置之间的映射,这通常利用关联数组实现,拥有两种表现形式:
+
+```sql
+    inverted file index:{单词,单词所在文档的id}
+
+    full inverted index:{单词,(单词所在文档的id,再具体文档中的位置)}
+```
+
+创建索引之后可以在索引中查找与关键词匹配的文档列表。可以使用布尔检索、向量空间模型或其他检索算法来计算文档与关键词的相关性,并返回匹配度高的文档结果。
+
+## binlog与主从复制
+
+binlog 文件是记录了所有数据库表结构变更和表数据修改的日志,不会记录查询类的操作,比如 SELECT 和 SHOW 操作。
+
+binlog日志可以用于在主从数据库之间复制数据,从而实现数据的高可用和负载均衡等功能。
+MySQL的binlog日志有三种格式,分别是Statement格式、Row格式和Mixed格式。它们之间的区别如下:
+
+* STATEMENT:每一条修改数据的 SQL 都会被记录到 binlog 中(相当于记录了逻辑操作,所以针对这种格式, binlog 可以称为逻辑日志),主从复制中 slave 端再根据 SQL 语句重现。但 STATEMENT 有动态函数的问题,比如你用了 uuid 或者 now 这些函数,你在主库上执行的结果并不是你在从库执行的结果,这种随时在变的函数会导致复制的数据不一致;
+* ROW:记录行数据最终被修改成什么样了(这种格式的日志,就不能称为逻辑日志了),不会出现 STATEMENT 下动态函数的问题。但 ROW 的缺点是每行数据的变化结果都会被记录,比如执行批量 update 语句,更新多少行数据就会产生多少条记录,使 binlog 文件过大,而在 STATEMENT 格式下只会记录一个 update 语句而已;
+* MIXED:包含了 STATEMENT 和 ROW 模式,它会根据不同的情况自动使用 ROW 模式和 STATEMENT 模式;
+
+MySQL 的主从复制依赖于 binlog ,也就是记录 MySQL 上的所有变化并以二进制形式保存在磁盘上。复制的过程就是将 binlog 中的数据从主库传输到从库上。
+
+这个过程一般是**异步**的,也就是主库上执行事务操作的线程不会等待复制 binlog 的线程同步完成。
+
+![MySQL 主从复制过程](assets/主从复制过程.drawio.png)
+
+MySQL 集群的主从复制过程梳理成 3 个阶段:
+
+- **写入 Binlog**:主库写 binlog 日志,提交事务,并更新本地存储数据。
+- **同步 Binlog**:把 binlog 复制到所有从库上,每个从库把 binlog 写到暂存日志中。
+- **回放 Binlog**:回放 binlog,并更新存储引擎中的数据。
+
+具体详细过程如下:
+
+- MySQL 主库在收到客户端提交事务的请求之后,会先写入 binlog,再提交事务,更新存储引擎中的数据,事务提交完成后,返回给客户端“操作成功”的响应。
+- 从库会创建一个专门的 I/O 线程,连接主库的 log dump 线程,来接收主库的 binlog 日志,再把 binlog 信息写入 relay log 的中继日志里,再返回给主库“复制成功”的响应。
+- 从库会创建一个用于回放 binlog 的线程,去读 relay log 中继日志,然后回放 binlog 更新存储引擎中的数据,最终实现主从的数据一致性。
+- 当一个事务在 MySQL 主库上被回滚时,相应的回滚操作会被写入 binlog,以确保主从复制和数据一致性。
+
+在完成主从复制之后,你就可以在写数据时只写主库,在读数据时只读从库,这样即使写请求会锁表或者锁记录,也不会影响读请求的执行。
+
+> 从库是不是越多越好?
+
+不是的。
+
+因为从库数量增加,从库连接上来的 I/O 线程也比较多,**主库也要创建同样多的 log dump 线程来处理复制的请求,对主库资源消耗比较高,同时还受限于主库的网络带宽**。
+
+所以在实际使用中,一个主库一般跟 2~3 个从库(1 套数据库,1 主 2 从 1 备主),这就是一主多从的 MySQL 集群结构。
+
+> MySQL 主从复制还有哪些模型?
+
+主要有三种:
+
+- **同步复制**:MySQL 主库提交事务的线程要等待所有从库的复制成功响应,才返回客户端结果。这种方式在实际项目中,基本上没法用,原因有两个:一是性能很差,因为要复制到所有节点才返回响应;二是可用性也很差,主库和所有从库任何一个数据库出问题,都会影响业务。
+- **异步复制**(默认模型):MySQL 主库提交事务的线程并不会等待 binlog 同步到各从库,就返回客户端结果。这种模式一旦主库宕机,数据就会发生丢失。
+- **半同步复制**:MySQL 5.7 版本之后增加的一种复制方式,介于两者之间,事务线程不用等待所有的从库复制成功响应,只要一部分复制成功响应回来就行,比如一主二从的集群,只要数据成功复制到任意一个从库上,主库的事务线程就可以返回给客户端。这种**半同步复制的方式,兼顾了异步复制和同步复制的优点,即使出现主库宕机,至少还有一个从库有最新的数据,不存在数据丢失的风险**。
+
+## undo log
+
+ **undo log(回滚日志),它保证了事务的 ACID 特性中的原子性(Atomicity)**。
+
+![回滚事务](assets/回滚事务.png)
+
+每当 InnoDB 引擎对一条记录进行操作(修改、删除、新增)时,要把回滚时需要的信息都记录到 undo log 里,比如:
+
+- 在**插入**一条记录时,要把这条记录的主键值记下来,这样之后回滚时只需要把这个主键值对应的记录**删掉**就好了;
+- 在**删除**一条记录时,要把这条记录中的内容都记下来,这样之后回滚时再把由这些内容组成的记录**插入**到表中就好了;
+- 在**更新**一条记录时,要把被更新的列的旧值记下来,这样之后回滚时再把这些列**更新为旧值**就好了。
+
+一条记录的每一次更新操作产生的 undo log 格式都有一个 roll_pointer 指针和一个 trx_id 事务id:
+
+- 通过 trx_id 可以知道该记录是被哪个事务修改的;
+- 通过 roll_pointer 指针可以将这些 undo log 串成一个链表,这个链表就被称为版本链;
+
+版本链如下图:
+
+![版本链](assets/版本链.png)
+
+因此,undo log 两大作用:
+
+- **实现事务回滚,保障事务的原子性**。事务处理过程中,如果出现了错误或者用户执 行了 ROLLBACK 语句,MySQL 可以利用 undo log 中的历史数据将数据恢复到事务开始之前的状态。
+- **实现 MVCC(多版本并发控制)关键因素之一**。MVCC 是通过 ReadView + undo log 实现的。undo log 为每条记录保存多份历史数据,MySQL 在执行快照读(普通 select 语句)的时候,会根据事务的 Read View 里的信息,顺着 undo log 的版本链找到满足其可见性的记录。
+
+## Buffer Pool?
+
+Innodb 存储引擎缓冲池**(Buffer Pool)**
+
+![Buffer Poo](assets/缓冲池.drawio.png)
+
+有了 Buffer Poo 后:
+
+- 当读取数据时,如果数据存在于 Buffer Pool 中,客户端就会直接读取 Buffer Pool 中的数据,否则再去磁盘中读取。
+- 当修改数据时,如果数据存在于 Buffer Pool 中,那直接修改 Buffer Pool 中数据所在的页,然后将其页设置为脏页(该页的内存数据和磁盘上的数据已经不一致),为了减少磁盘I/O,不会立即将脏页写入磁盘,后续由后台线程选择一个合适的时机将脏页写入到磁盘。
+
+### Buffer Pool 缓存什么?
+
+InnoDB 会把存储的数据划分为若干个「页」,以页作为磁盘和内存交互的基本单位,一个页的默认大小为 16KB。因此,Buffer Pool 同样需要按「页」来划分。
+
+在 MySQL 启动的时候,**InnoDB 会为 Buffer Pool 申请一片连续的内存空间,然后按照默认的`16KB`的大小划分出一个个的页, Buffer Pool 中的页就叫做缓存页**。此时这些缓存页都是空闲的,之后随着程序的运行,才会有磁盘上的页被缓存到 Buffer Pool 中。
+
+所以,MySQL 刚启动的时候,你会观察到使用的虚拟内存空间很大,而使用到的物理内存空间却很小,这是因为只有这些虚拟内存被访问后,操作系统才会触发缺页中断,申请物理内存,接着将虚拟地址和物理地址建立映射关系。
+
+Buffer Pool 除了缓存「索引页」和「数据页」,还包括了 Undo 页,插入缓存、自适应哈希索引、锁信息等等。
+
+
+
+> **Undo 页是记录什么?**
+
+开启事务后,InnoDB 层更新记录前,首先要记录相应的 undo log,如果是更新操作,需要把被更新的列的旧值记下来,也就是要生成一条 undo log,undo log 会写入 Buffer Pool 中的 Undo 页面。
+
+> **查询一条记录,就只需要缓冲一条记录吗?**
+
+不是的。
+
+当我们查询一条记录时,InnoDB 是会把整个页的数据加载到 Buffer Pool 中,将页加载到 Buffer Pool 后,再通过页里的「页目录」去定位到某条具体的记录。
+
+
+
+## redo log
+
+为了防止断电导致数据丢失的问题,当有一条记录需要更新的时候,InnoDB 引擎就会先更新内存(同时标记为脏页),然后将本次对这个页的修改以 redo log 的形式记录下来,**这个时候更新就算完成了**。
+
+后续,InnoDB 引擎会在适当的时候,由后台线程将缓存在 Buffer Pool 的脏页刷新到磁盘里,这就是 **WAL (Write-Ahead Logging)技术**。
+
+**WAL 技术指的是, MySQL 的写操作并不是立刻写到磁盘上,而是先写日志,然后在合适的时间再写到磁盘上**。
+
+过程如下图:
+
+![img](assets/wal.png)
+
+> **什么是 redo log?**
+
+redo log 是物理日志,记录了某个数据页做了什么修改,比如**对 XXX 表空间中的 YYY 数据页 ZZZ 偏移量的地方做了AAA 更新**,每当执行一个事务就会产生这样的一条或者多条物理日志。
+
+在事务提交时,只要先将 redo log 持久化到磁盘即可,可以不需要等到将缓存在 Buffer Pool 里的脏页数据持久化到磁盘。
+
+当系统崩溃时,虽然脏页数据没有持久化,但是 redo log 已经持久化,接着 MySQL 重启后,可以根据 redo log 的内容,将所有数据恢复到最新的状态。
+
+> **被修改 Undo 页面,需要记录对应 redo log 吗?**
+
+需要的。
+
+开启事务后,InnoDB 层更新记录前,首先要记录相应的 undo log,如果是更新操作,需要把被更新的列的旧值记下来,也就是要生成一条 undo log,undo log 会写入 Buffer Pool 中的 Undo 页面。
+
+不过,**在内存修改该 Undo 页面后,需要记录对应的 redo log**。
+
+> **redo log 和 undo log 区别在哪?**
+
+这两种日志是属于 InnoDB 存储引擎的日志,它们的区别在于:
+
+- redo log 记录了此次事务「**完成后**」的数据状态,记录的是更新**之后**的值;
+- undo log 记录了此次事务「**开始前**」的数据状态,记录的是更新**之前**的值;
+
+事务提交之前发生了崩溃,重启后会通过 undo log 回滚事务,事务提交之后发生了崩溃,重启后会通过 redo log 恢复事务,如下图:
+
+![事务恢复](assets/事务恢复.png)
+
+所以有了 redo log,再通过 WAL 技术,InnoDB 就可以保证即使数据库发生异常重启,之前已提交的记录都不会丢失,这个能力称为 **crash-safe**(崩溃恢复)。可以看出来, **redo log 保证了事务四大特性中的持久性**。
+
+> **redo log 要写到磁盘,数据也要写磁盘,为什么要多此一举?**
+
+写入 redo log 的方式使用了追加操作, 所以磁盘操作是**顺序写**,而写入数据需要先找到写入位置,然后才写到磁盘,所以磁盘操作是**随机写**。
+
+磁盘的「顺序写 」比「随机写」 高效的多,因此 redo log 写入磁盘的开销更小。
+
+针对「顺序写」为什么比「随机写」更快这个问题,可以比喻为你有一个本子,按照顺序一页一页写肯定比写一个字都要找到对应页写快得多。
+
+可以说这是 WAL 技术的另外一个优点:**MySQL 的写操作从磁盘的「随机写」变成了「顺序写」**,提升语句的执行性能。这是因为 MySQL 的写操作并不是立刻更新到磁盘上,而是先记录在日志上,然后在合适的时间再更新到磁盘上 。
+
+至此, 针对为什么需要 redo log 这个问题我们有两个答案:
+
+- **实现事务的持久性,让 MySQL 有 crash-safe 的能力**,能够保证 MySQL 在任何时间段突然崩溃,重启后之前已提交的记录都不会丢失;
+- **将写操作从「随机写」变成了「顺序写」**,提升 MySQL 写入磁盘的性能。
+
+> **产生的 redo log 是直接写入磁盘的吗?**
+
+不是的。
+
+实际上, 执行一个事务的过程中,产生的 redo log 也不是直接写入磁盘的,因为这样会产生大量的 I/O 操作,而且磁盘的运行速度远慢于内存。
+
+所以,redo log 也有自己的缓存—— **redo log buffer**,每当产生一条 redo log 时,会先写入到 redo log buffer,后续在持久化到磁盘如下图:
+
+![事务恢复](assets/redologbuf.webp)
+
+redo log buffer 默认大小 16 MB,可以通过 `innodb_log_Buffer_size` 参数动态的调整大小,增大它的大小可以让 MySQL 处理「大事务」是不必写入磁盘,进而提升写 IO 性能。
+
+### redo log 什么时候刷盘?
+
+缓存在 redo log buffer 里的 redo log 还是在内存中,它什么时候刷新到磁盘?
+
+主要有下面几个时机:
+
+- MySQL 正常关闭时;
+- 当 redo log buffer 中记录的写入量大于 redo log buffer 内存空间的一半时,会触发落盘;
+- InnoDB 的后台线程每隔 1 秒,将 redo log buffer 持久化到磁盘。
+- 每次事务提交时都将缓存在 redo log buffer 里的 redo log 直接持久化到磁盘(这个策略可由 innodb_flush_log_at_trx_commit 参数控制,下面会说)。
+
+## redo log和binlog区别
+
+binlog和redolog都是用于MySQL数据库的日志。它们都可以用于数据恢复,但是它们的使用场景和恢复方法有所不同。
+
+binlog是MySQL的二进制日志,它记录了所有对MySQL数据库的修改操作,包括插入、更新和删除等。binlog可以用于恢复MySQL数据库到指定的时间点或者指定的事务。具体来说,可以使用mysqlbinlog命令将binlog文件解析成SQL语句,然后再执行这些SQL语句,从而恢复MySQL数据库的状态。
+
+redolog是MySQL的重做日志,它记录了所有对MySQL数据库的修改操作,但是只记录了物理操作,比如页的修改。redolog可以用于恢复MySQL数据库的崩溃恢复,即在MySQL崩溃后,通过重做日志,将数据库恢复到最近一次提交的状态。具体来说,可以使用innodb_recovery命令来进行崩溃恢复,该命令会根据重做日志来恢复数据库。
+
+因此,binlog和redolog都可以用于数据恢复,但是它们的使用场景和恢复方法有所不同。binlog主要用于数据恢复到指定时间点或者指定事务,而redolog主要用于MySQL的崩溃恢复。
+
+## mysql优化慢SQL
+
+### 开启慢查询日志
+
+首先开启慢查询日志,由参数`slow_query_log`决定是否开启,在MySQL命令行下输入下面的命令:
+
+```mysql
+set global slow_query_log=on;
+```
+
+或者可以使用druid连接池去监控
+
+其次设置一个慢查询阈值
+
+```mysql
+set global long_query_time=1;
+```
+
+只要你的SQL实际执行时间超过了这个阈值,就会被记录到慢查询日志里面。这个阈值默认是10s,线上业务一般建议把`long_query_time`设置为1s,如果某个业务的MySQL要求比较高的QPS,可设置慢查询为0.1s。
+
+最后通过
+
+```mysql
+show global variables like 'slow_query_log_file'
+```
+
+语句可以找到慢查询的日志
+
+### 使用**explain**分析sql执行计划
+
+* select_type
+
+![img](assets/v2-98b72fd8e29df55aecdafb8deff0312f_720w.webp)
+
+* type
+
+![img](assets/v2-4c45bde8970caa0205d64b50095169c4_720w.webp)
+
+* Extra:
+
+![img](assets/v2-3ab6401c24be71551d1138762ed1a307_720w.webp)
+
+### 关键字优化
+
+* 因为只有在内连接的时候,and就一并筛选,而Where是将两张表先合并一起,再做筛选
+* 优化value的插入方式,即insert (a, b) (1, ,2,3,4)
+* 避免索引失效
+* 避免使用not null not in 之类的关键字,均会导致索引失效
+
+## CHAR和VARCHAR的区别
+
+在MySQL中,`CHAR`和`VARCHAR`都是用于存储文本数据的数据类型,它们之间有以下区别:
+
+1. 存储方式:`CHAR`类型是固定长度的,当存储数据时,会使用固定的空间。例如,如果定义一个`CHAR(10)`类型的字段,无论实际存储的数据长度是多少,都会占用10个字符的空间。而`VARCHAR`类型是可变长度的,只会占用实际存储的数据长度加上额外的存储空间(1或2个字节用于记录数据长度),对于较短的数据,它占用的空间会更小。
+2. 存储效率:由于`CHAR`类型是固定长度的,所以在存储和检索时效率相对较高。而`VARCHAR`类型由于长度可变,可能会造成额外的存储空间和内存开销,所以在存储和检索大量数据时,效率可能稍低。
+3. 数据填充:对于`CHAR`类型,如果实际存储的数据长度小于定义的长度,会使用空格进行填充以达到指定长度。而`VARCHAR`类型不会进行填充。
+4. 索引和排序:在MySQL中,对于`CHAR`类型的列,可以更好地利用索引和排序的性能,因为它的长度固定,查询时可以更快地定位数据。而`VARCHAR`类型由于长度可变,可能会影响索引和排序的效率。
+
+## 索引失效场景
+
+* 最左前缀原则:要求建立索引的一个列都不能缺失,否则会出现索引失效
+
+* 索引列上的计算,函数、类型转换(列类型是字符串在条件中需要使用引号,否则不走索引)、均会导致索引失效:,索引的数据结构只能对原值做索引
+
+* 索引列中使用 is not null 会导致索引列失效:在where 语句种筛选 idx is null 时,由于索引字段不为空,所以该条件失效,无法查询;在where 语句种筛选 idx is not null 时,由于索引字段本身不为空,所以该条件也失效,会造成全表扫描;
+
+* 索引列中使用 like 查询的前以 % 开头会导致索引列失效。
+
+* 索引列用 or 连接时会导致索引失效:如果条件中有or,只要其中一个条件没有索引,其他字段有索引也不会使用。
+
+## mysql分库分表历史数据如何查询
+
+* 直接进行迁移:记录时间戳,使用定时任务去扫描
+* 平滑迁移:只插入,旧表数据不动,插入时候直接加上扩容倍数。查询直接分批查询。
+
+## mysql分库分表物理层面优化
+
+* IO瓶颈
+
+磁盘读IO瓶颈,热点数据太多,数据库缓存放不下,每次查询时会产生大量的IO,降低查询速度 ->  分库和垂直分表。
+
+网络IO瓶颈,请求的数据太多,网络带宽不够 ->  分库。
+
+* CPU瓶颈
+
+SQL问题,如SQL中包含join,group by,order by,非索引字段条件查询等,增加CPU运算的操作 -> SQL优化,建立合适的索引,在业务Service层进行业务计算。
+
+单表数据量太大,查询时扫描的行太多,SQL效率低,CPU率先出现瓶颈 ->  水平分表。
+
+* 存储瓶颈
+
+关系型数据库多以B+树类型的索引,在数据量超过阈值的情况,索引深度的增加使得磁盘访问的IO次数增加,导致性能下降,同时,高并发访问使得集中数据库成为系统瓶颈。
+
+## 既然Hash比B+树更快,为什么MySQL用B+树来存储索引呢?
+
+MySQL中存储索引用到的数据结构是B+树,B+树的查询时间跟树的高度有关,是log(n),如果用hash存储,那么查询时间是O(1)。
+
+采用Hash来存储确实要更快,但是采用B+树来存储索引的原因主要有以下两点:
+
+一、**从内存角度上说**,数据库中的索引一般是在磁盘上,数据量大的情况可能无法一次性装入内存,B+树的设计可以允许数据分批加载。
+
+二、**从业务场景上说**,如果只选择一个数据那确实是hash更快,但是数据库中经常会选中多条,这时候由于B+树索引有序,并且又有链表相连,它的查询效率比hash就快很多了。
+
+## B+树插入流程
+
+B+树是B树的一种变形形式,一颗B+树包含根节点、内部节点和叶子节点,B+树上的叶子节点存储关键字以及相应记录的地址,叶子节点以上各层作为索引使用。
+
+一棵m阶的B+树定义如下:
+
+* 1)根结点最少包含1个关键字个数,最多包含m-1个关键字;
+* 2)B+树内部结点不保存数据,只用于索引,所有数据(或者说记录)都保存在叶子结点中;
+* 3)内部结点最少有ceil(m / 2) (向上取整)- 1个关键字,最多有m-1个关键字(或者说内部结点最多有m个子树);
+* 4)内部结点中的key都按照从小到大的顺序排列,对于内部结点中的一个key,左树中的所有key都小于它,右子树中的key都大于等于它,叶子结点中的记录也按照key的大小排列;
+* 5)每个叶子结点都存有相邻叶子结点的指针,叶子结点本身依关键字的大小自小而大顺序连接;
+  如下图是一颗标准的5阶B+树:
+
+![image-20230824174350063](assets/image-20230824174350063.png)
+
+![image-20230824174809579](assets/image-20230824174809579.png)
+
+![img](assets/20201104163915661.png)
+
+​	
+
+下面我们通过一个简单的示例说明B+树的详细构建过程:
+
+我们以构建一个5阶B+树为例,根据B+树特性,最少包含2个关键字,最多可以包含4个关键字,当不满足上面条件的时候,可能就需要进行分裂操作了。
+
+![img](assets/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1dlaXhpYW9odWFp,size_16,color_FFFFFF,t_70-169287061300535.png)
+
+## 数据库三大范式
+
+* 第一范式:列不可再分
+* 第二范式:属性完全依赖主键
+* 第三范式:属性不依赖于其他非主键,属性直接依赖于主键
+
+## limit与深度翻页
+
+最常见的分页写法就是使用limit,在分页查询时,会在 LIMIT 后面传两个参数,一个是偏移量(offset),一个是获取的条数(limit)。
+
+实现方式是先查询offset+limit条数据,再将offset条数据丢弃给用户返回剩下的limit条数据。比如limit 10000,10实际上是mysql查找到前10010条数据,之后丢弃前面的10000行后再返回
+
+这样子当偏移量很小时,查询速度很快,但是随着 offset 变大时,查询速度会越来越慢,因为查找的数据越来越多
+
+### 优化
+
+- 方式一:
+
+```mysql
+select * from t1 where id >= 300000 order by id limit 10
+```
+
+避免了扫描前offset条记录
+
+但是每次查询都需要拿到上一页的最大/小id。比如当前在第3页,需要查询第5页的数据就没办法了
+
+* 方式二:
+
+结合普通limit与方式一,解决方式二的问题,但是offset要尽量小
+
+```mysql
+select * from t1 where id > 300000 order by id limit 10, 10
+```
+
+* 方式三:
+
+```mysql
+select * from t1 where id > (select id from t1 order by id limit 300000, 1) limit 10
+```
+
+## MySQL中 IS NULL、IS NOT NULL、不等于, 能用上索引吗?
+
+**MySQL中决定使不使用某个索引执行查询的依据就是成本够不够小,如果null值很多,还是会用到索引的。**
+
+## MySQL允许在唯一索引字段中添加多个NULL值
+
+ 在sql server中,唯一索引字段不能出现多个null值 在mysql 的innodb引擎中,是允许在唯一索引的字段中出现多个null值的。 根据NULL的定义,**NULL表示的是未知,因此两个NULL比较的结果既不相等,也不不等,结果仍然是未知。**根据这个定义,多个NULL值的存在应该不违反唯一约束,所以是合理的,在oracel也是如此。
+
+## mysql索引为什么不能为null
+
+会引起歧义,就不允许
+
+## 为什么是2千万?
+
+假设
+
+- 非叶子节点内指向其他页的数量为 x
+- 叶子节点内能容纳的数据行数为 y
+- B+ 数的层数为 z
+
+一页是16K,**页又一些File Header (38 byte)、Page Header (56 Byte)、Infimum + Supermum(26 byte)、File Trailer(8byte), 再加上页目录,大概 1k 左右。** 剩下 15k 用于存数据,主键我们假设是 Bigint (8 byte), 而页号也是固定的(4Byte)那么索引页中的一条数据也就是 12byte。
+
+所以非叶子节点内指向其他页的数量为 x , x=15*1024/12≈1280 行。
+
+叶子节点和非叶子节点的结构是一样的,同理,能放数据的空间也是 15k。
+
+但是叶子节点中存放的是真正的行数据,这个影响的因素就会多很多,比如,字段的类型,字段的数量。每行数据占用空间越大,页中所放的行数量就会越少。
+
+这边我们暂时按一条行数据 1k 来算,那一页就能存下 15 条,Y = 15*1024/1000 ≈15。
+
+算到这边了,是不是心里已经有谱了啊。
+
+根据上述的公式,Total =x^(z-1) *y,已知 x=1280,y=15:
+
+- 假设 B+ 树是两层,那就是 z = 2, Total = (1280 ^1 )*15 = 19200
+- 假设 B+ 树是三层,那就是 z = 3, Total = (1280 ^2) *15 = 24576000 (约 2.45kw)

BIN
面经/问答/assets/03eacec67cc58ff8d5819d0872ddd41e.png


BIN
面经/问答/assets/04163db3b7ca4b4c8fbfdf4e7253a98ftplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
面经/问答/assets/056c87751b9dd7b56f4264240fe96d00.png


BIN
面经/问答/assets/13e4361407ba46979e802eaa654dcf67.png


BIN
面经/问答/assets/1418b09699fe4614a594a565c55055d5tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
面经/问答/assets/16c1e0e2878c44dctplv-t2oaga2asx-jj-mark3024000q75.awebp


BIN
面经/问答/assets/16c1e0e28889eafftplv-t2oaga2asx-jj-mark3024000q75.awebp


BIN
面经/问答/assets/16c1e0e289a351b2tplv-t2oaga2asx-jj-mark3024000q75.awebp


BIN
面经/问答/assets/16c1e0e289f9213etplv-t2oaga2asx-jj-mark3024000q75.awebp


BIN
面经/问答/assets/16c1e0e28aee99a1tplv-t2oaga2asx-jj-mark3024000q75.awebp


BIN
面经/问答/assets/16c1e0e2ca893b49tplv-t2oaga2asx-jj-mark3024000q75.awebp


BIN
面经/问答/assets/16c1e0e2d7df4fbftplv-t2oaga2asx-jj-mark3024000q75.awebp


BIN
面经/问答/assets/16c1e0e2db1c4812tplv-t2oaga2asx-jj-mark3024000q75-16934721993069.awebp


BIN
面经/问答/assets/16c1e0e2db1c4812tplv-t2oaga2asx-jj-mark3024000q75.awebp


BIN
面经/问答/assets/16c1e0e2e2a2835etplv-t2oaga2asx-jj-mark3024000q75.awebp


BIN
面经/问答/assets/16c1e0e2e507aec0tplv-t2oaga2asx-jj-mark3024000q75.awebp


BIN
面经/问答/assets/16c1e0e3178398fctplv-t2oaga2asx-jj-mark3024000q75.awebp


BIN
面经/问答/assets/16c1e26a5ecf086etplv-t2oaga2asx-jj-mark3024000q75.awebp


BIN
面经/问答/assets/1cc7401143e79383ead96582ac11b615.png


BIN
面经/问答/assets/20201104163915661.png


BIN
面经/问答/assets/20201104164026393.png


BIN
面经/问答/assets/20201104164057943.png


BIN
面经/问答/assets/202308021211012.jpeg


BIN
面经/问答/assets/202308021212079.jpeg


BIN
面经/问答/assets/202308021212511.jpeg


BIN
面经/问答/assets/202308021218967.jpeg


BIN
面经/问答/assets/2164474-20210716210057908-1704850787.png


BIN
面经/问答/assets/22c7fe97ce5d3c382b08d83a4d8a5b96.png


BIN
面经/问答/assets/2306520394.png


BIN
面经/问答/assets/24-先来先服务.jpg


BIN
面经/问答/assets/25-最短作业优先算法.jpg


BIN
面经/问答/assets/2535cfeb9cfb44d4a0a04506f09f7485tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
面经/问答/assets/26-响应比公式.jpg


BIN
面经/问答/assets/26f88373d8454682b9e0c1d4fd1611b4-20230309233114856.png


BIN
面经/问答/assets/27-时间片轮询.jpg


BIN
面经/问答/assets/28-多级队列.jpg


BIN
面经/问答/assets/2802786ab4f52c1e248904e5cef33a74.png


BIN
面经/问答/assets/2ae0ed790c7e7403f215acb2bd82e884.png


BIN
面经/问答/assets/2b7231b6aabb9a9a2e2390ab3a280b2d-20230309232920063.png


BIN
面经/问答/assets/2db4831516b9a8b79f833cf0593c1f12.png


BIN
面经/问答/assets/2e2b95eebf60b6d03f6c1476f4d7c697.png


BIN
面经/问答/assets/30c2c70721c12f9c140358fbdc5f2282.png


BIN
面经/问答/assets/316b81a42ea843a192cc2f3578fbdb81tplv-k3u1fbpfcp-zoom-in-crop-mark1512000-16927837871897.awebp


BIN
面经/问答/assets/316b81a42ea843a192cc2f3578fbdb81tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
面经/问答/assets/31b9745a2fa94fb693a7ea1257aa5f7ftplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
面经/问答/assets/33f858652afc4be6bb1d7b1f1dc33eaatplv-k3u1fbpfcp-zoom-in-crop-mark1512000-169278452952817.awebp


BIN
面经/问答/assets/33f858652afc4be6bb1d7b1f1dc33eaatplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
面经/问答/assets/35820959e8cf4376391c427ed7f81495.png


BIN
面经/问答/assets/3a6cb4e3f27241d3b09b4766bb0b1124.png


BIN
面经/问答/assets/3层跳表-跨度.drawio.png


BIN
面经/问答/assets/3层跳表-跨度.png


BIN
面经/问答/assets/454a8228a6549176ad7e0484fba3c92b.png


BIN
面经/问答/assets/47e6c8fbc17fd6c89bdfcb5eedaaacff.png


BIN
面经/问答/assets/4845008abadaa871613873f5ffdcb542.png


BIN
面经/问答/assets/4d850bfe8d712d3d67ff13e59b919452.png


BIN
面经/问答/assets/4ef8691d67eb1eb53217099d0a691eb5.png


BIN
面经/问答/assets/516738c4058cdf9109e40a7812ef4239.png


BIN
面经/问答/assets/517e2f7939394b3ca35936702a107f07tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
面经/问答/assets/559260f5ef944cd1a146d07308275b89tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
面经/问答/assets/5e9e65a4a59b3688fa37cadbd87bb5ac.png


BIN
面经/问答/assets/60d6b91f49ac4d11bee43f86f33566d6tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
面经/问答/assets/6a68be69f6b64ad1a8df234d9f0772detplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
面经/问答/assets/775865f6bd894dfba8d373ee54d79af1.png


BIN
面经/问答/assets/788acb3c73174c42b603fe67e96c89f5tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
面经/问答/assets/7d45e677f6c2428d9b9db7022416fe26tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
面经/问答/assets/80a2bcb823e04e05a10c8f19de2930b9tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
面经/问答/assets/8febac10b14bed16cb96d1d944cd08da.png


BIN
面经/问答/assets/955fdfb94c234e32939c76954fd28a56tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
面经/问答/assets/98987d9417b2bab43087f45fc959d32a-20230309232253633.png


BIN
面经/问答/assets/9ebde5c11ad69447314c216acf188fc8.png


BIN
面经/问答/assets/a3e7d217ecb825e94bdc577a467eb29d.png


BIN
面经/问答/assets/a6e0e622b7384ac78f733e471b280c27tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
面经/问答/assets/a851f56a384b4a0f9da76644d645ae1ftplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
面经/问答/assets/arch-x-reduce-2.png


BIN
面经/问答/assets/arch-x-reduce-3.png


BIN
面经/问答/assets/arch-x-reduce-31-169347359783720.png


BIN
面经/问答/assets/b52e004bd4654cb1b51cdb409182156ftplv-k3u1fbpfcp-zoom-in-crop-mark1512000.awebp


BIN
面经/问答/assets/b5681d905102439aa1a40412100da566.png


BIN
面经/问答/assets/c55029a32a6448d9aa35bb3de6efcecatplv-k3u1fbpfcp-zoom-in-crop-mark4536000.awebp


Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff