大家好,我是二哥呀。
在牛客上刷到一条比较离谱的帖子,一位牛友说自己收到一个 offer,需要外包到新疆的乌鲁木齐,但是薪资足足有 60k*13,估算下来一年 78 万到手。
然后评论区就非常精彩了,有牛友回复说这个价位外派到月球都可以,甚至还有更离谱的,“别说新疆了,让我去西伯利亚喂狼都可以”(😂)。
我有一个老乡,为了孩子考大学,前几年举家搬迁到了新疆的乌鲁木齐,她说在那里生活其实挺舒服的,还邀请我们有机会去那里旅游。
星球里之前刚好有一位球友在乌鲁木齐,不过面试的是一家小厂,薪资也不是特别高,但对于他本人来说,觉得已经很满意了,那接下来就把他当时的面试题分享出来,对新疆工作感兴趣或者好奇的同学可以参考一下。
我已经将面经收录在了《二哥的Java 面试指南》中,可以看得出,还是二哥一直强调的 Java 后端四大件,还在冲刺春招和暑期实习的同学可以收藏起来,好做到知彼知己百战不殆。
数据库文件是存储在磁盘上的,磁盘 I/O 是数据库操作中最耗时的部分之一。没有索引时,数据库会进行全表扫描(Sequential Scan),这意味着它必须读取表中的每一行数据来查找匹配的行(时间效率为 O(n))。当表的数据量非常大时,就会导致大量的磁盘 I/O 操作。
有了索引,就可以直接跳到索引指示的数据位置,而不必扫描整张表,从而大大减少了磁盘 I/O 操作的次数。
MySQL 的 InnoDB 存储引擎默认使用 B+ 树来作为索引的数据结构,而 B+ 树的查询效率非常高,时间复杂度为 O(logN)。
索引文件相较于数据库文件,体积小得多,查到索引之后再映射到数据库记录,查询效率就会高很多。
就好像我们通过书的目录,去查找对应的章节内容一样。
三分恶面渣逆袭:索引加快查询远离
B 树是一种自平衡的多路查找树,和红黑树、二叉平衡树不同,B 树的每个节点可以有 m 个子节点,而红黑树和二叉平衡树都只有 2 个。
换句话说,红黑树、二叉平衡树是细高个,而 B 树是矮胖子。
二哥的 Java 进阶之路:B 树
内存和磁盘在进行 IO 读写的时候,有一个最小的逻辑单元,叫做页(Page),页的大小一般是 4KB。
二哥的 Java 进阶之路:IO 读写
那为了提高读写效率,从磁盘往内存中读数据的时候,一次会读取至少一页的数据,比如说读取 2KB 的数据,实际上会读取 4KB 的数据;读取 5KB 的数据,实际上会读取 8KB 的数据。我们要尽量减少读写的次数。
因为读的次数越多,效率就越低。就好比我们在工地上搬砖,一次搬 10 块砖肯定比一次搬 1 块砖的效率要高,反正我每次都搬 10 块(😁)。
对于红黑树、二叉平衡树这种细高个来说,每次搬的砖少,因为力气不够嘛,那来回跑的次数就越多。
是这个道理吧,树越高,意味着查找数据时就需要更多的磁盘 IO,因为每一层都可能需要从磁盘加载新的节点。
用户1260737:二叉树
B 树的节点大小通常与页的大小对齐,这样每次从磁盘加载一个节点时,可以正好是一个页的大小。因为 B 树的节点可以有多个子节点,可以填充更多的信息以达到一页的大小。
用户1260737:B 树
B 树的一个节点通常包括三个部分:
不过,正所谓“祸兮福所倚,福兮祸所伏”,正是因为 B 树的每个节点上都存了数据,就导致每个节点能存储的键值和指针变少了,因为每一页的大小是固定的,对吧?
于是 B+树就来了,B+树的非叶子节点只存储键值,不存储数据,而叶子节点存储了所有的数据,并且构成了一个有序链表。
用户1260737:B 树
这样做的好处是,非叶子节点上由于没有存储数据,就可以存储更多的键值对,树就变得更加矮胖了,于是就更有劲了,每次搬的砖也就更多了(😂)。
由此一来,查找数据进行的磁盘 IO 就更少了,查询的效率也就更高了。
再加上叶子节点构成了一个有序链表,范围查询时就可以直接通过叶子节点间的指针顺序访问整个查询范围内的所有记录,而无需对树进行多次遍历。
Spring MVC 是基于模型-视图-控制器的 Web 框架,它的工作流程也主要是围绕着 Model、View、Controller 这三个组件展开的。
三分恶面渣逆袭:Spring MVC的工作流程
图片来源于网络:SpringMVC工作流程图
_未来可期:SpringMVC工作流程图
①、发起请求:客户端通过 HTTP 协议向服务器发起请求。
②、前端控制器:这个请求会先到前端控制器 DispatcherServlet,它是整个流程的入口点,负责接收请求并将其分发给相应的处理器。
③、处理器映射:DispatcherServlet 调用 HandlerMapping 来确定哪个 Controller 应该处理这个请求。通常会根据请求的 URL 来确定。
④、处理器适配器:一旦找到目标 Controller,DispatcherServlet 会使用 HandlerAdapter 来调用 Controller 的处理方法。
⑤、执行处理器:Controller 处理请求,处理完后返回一个 ModelAndView 对象,其中包含模型数据和逻辑视图名。
⑥、视图解析器:DispatcherServlet 接收到 ModelAndView 后,会使用 ViewResolver 来解析视图名称,找到具体的视图页面。
⑦、渲染视图:视图使用模型数据渲染页面,生成最终的页面内容。
⑧、响应结果:DispatcherServlet 将视图结果返回给客户端。
Spring MVC 虽然整体流程复杂,但是实际开发中很简单,大部分的组件不需要我们开发人员创建和管理,真正需要处理的只有 Controller 、View 、Model。
在前后端分离的情况下,步骤 ⑥、⑦、⑧ 会略有不同,后端通常只需要处理数据,并将 JSON 格式的数据返回给前端就可以了,而不是返回完整的视图页面。
Handler 一般就是指 Controller,Controller 是 Spring MVC 的核心组件,负责处理请求,返回响应。
Spring MVC 允许使用多种类型的处理器。不仅仅是标准的@Controller
注解的类,还可以是实现了特定接口的其他类(如 HttpRequestHandler 或 SimpleControllerHandlerAdapter 等)。这些处理器可能有不同的方法签名和交互方式。
HandlerAdapter 的主要职责就是调用 Handler 的方法来处理请求,并且适配不同类型的处理器。HandlerAdapter 确保 DispatcherServlet 可以以统一的方式调用不同类型的处理器,无需关心具体的执行细节。
在 Linux 环境下查找文件,有多种命令和方法可以使用。find 命令是最常用的文件查找工具之一,它可以在指定目录下递归查找符合条件的文件和目录。
例如:在当前目录及其子目录中查找名为 "example.txt" 的文件
find . -name "example.txt"
例如:查找 /home
目录中所有 .txt
结尾的文件:
find /home -name "*.txt"
例如:查找 /var/log
目录中修改时间在 7 天以前的 .log
文件
find /var/log -name "*.log" -mtime +7