首页 > 数据库 > 数据库开发技术 > 阿里技术面完后,一点也不慌
面试完不慌的底气一般来自哪里?手里有更牛批的Offer?稳了?
之前说过不管是BOSS直聘,还是拉勾等,很多挂着招聘需求的企业,但并不是真的还在招人了。
应该有至少三种情况:
A、已经招到了,HR忘记关闭。这种情况,看HR的活跃度,可以不投。
B、公司买了账号,纯粹是为了打个广告或者养号。这种即使有活跃度,也不会向你发送面试邀请,这种比较难辨别。
C、还有一种,可能就是HR背了KPI,要找点事做,囤人才简历。真的会筛简历,安排面试,不过后面就是没有HC了。
补充找工作相关常用术语
HR (Human Resources):人力资源部,负责招聘、培训、绩效评估等工作的部门。
HC (Headcount):职位编制或招聘名额,指公司计划招聘的职位数量。
JD (Job Description):职位描述,详细说明了职位的职责、要求和资格条件。
CV (Curriculum Vitae):简历,详细记录了个人教育背景、工作经验、技能等。
KPI (Key Performance Indicators):关键绩效指标,用于衡量员工或团队的工作表现。
AK (All Kill):指在面试中表现非常出色,全部答对或全部通过。
PA (Pass All):全部通过,指在所有环节(如笔试、面试、背景调查等)都通过。
AC (Accepted):接受,通常指申请或面试被接受。
回到这位校招的同学身上。
虽然这位同学一点也不慌,心态很好(找工作,就需要如此内心强大的)。
客观上就算还有HC,但是回答只有50%,阿里继续走流程的难度应该还是挺大的。
好在年轻,还有很多机会的,而且现在很多企业都很看好新一代的年轻人(别说只是因为工薪资低,因为大厂真的给得起),思维活跃、肯干、潜力无限。
那接下来我也整理该同学遇到的一些八股文,其他基础的就不列举了,无手撕,供各位校招朋友参考。
想必滚过烂熟了,三个核心要素是封装、继承和多态。不过这么回答肯定还不够。
还需要展开讲讲他们的概念和特性,才能让面试官认为你的基础很过关了,起码要介绍这三者是共同构成了面向对象编程的基本原则,使得代码更加模块化、可重用和易于维护吧。
1、封装(Encapsulation)
封装是指将数据(属性)和操作数据的方法(行为)绑定在一起,作为一个整体进行考虑,并尽可能隐藏对象的内部细节。
封装的主要目的是保护对象的内部状态,防止外部直接访问和修改,从而增加代码的安全性和稳定性。
特点:
private、protected、public)来控制类的成员变量和方法的可见性。getter 和 setter 方法)来访问和修改私有成员变量,从而在外部访问时进行必要的检查和验证。2、继承(Inheritance)
继承是指一个类(子类)可以继承另一个类(父类)的属性和方法。
通过继承,子类可以复用父类的代码,同时还可以添加新的属性和方法,或者重写父类的方法以实现不同的行为。
特点:
3、多态
多态是指同一个接口可以被不同的对象以不同的方式实现。多态包括方法重载(Overloading)和方法重写(Overriding)。
多态使得程序具有更高的灵活性和可扩展性。
特点:
先确保 pom.xml 文件中包含必要的配置信息,包括仓库的 URL、用户名和密码等。通常这些信息会放在 <distributionManagement> 部分。
然后在 Maven settings.xml 文件中(通常位于 ~/.m2/settings.xml),添加仓库的认证信息。
接下来就可以将项目代码发送到Maven仓库了,在项目根目录下运行 mvn deploy 命令,Maven 会根据 pom.xml 中的配置将构建产物上传到指定的仓库。
高分回答,可以先介绍下为什么需要分库分表:
1、分库
垂直分库:以表为依据,按照业务归属不同,将不同的表拆分到不同的库中。
水平分库:以字段为依据,按照一定策略(hash、range 等),将一个库中的数据拆分到多个库中。
2、分表
垂直分表:将表中的列拆分到不同的表中,每个表只包含原表的一部分列。适用于某些列访问频率很高而其他列很少被访问(主表、扩展表)的情况。
水平分表:根据某些字段的值将数据分布到不同的表中,这些表具有相同的结构。例如,可以根据用户ID的按一定策略(hash哈希值、range区间值、List列表值)对用户表进行分表。

原子性(Atomicity)
事务被视为不可分割的最小单元,事务的所有操作要么全部提交成功,要么全部失败回滚。
回滚可以用回滚日志(Undo Log)来实现,回滚日志记录着事务所执行的修改操作,在回滚时反向执行这些修改操作即可。
一致性(Consistency)
数据库在事务执行前后都保持一致性状态。在一致性状态下,所有事务对同一个数据的读取结果都是相同的。假如 A 账户给 B 账户转 10 块钱,不管成功与否,A 和 B 的总金额是不变的。
隔离性(Isolation)
一个事务所做的修改在最终提交以前,对其它事务是不可见的。
持久性(Durability)
一旦事务提交,则其所做的修改将会永远保存到数据库中。即使系统发生崩溃,事务执行的结果也不能丢失。
系统发生崩溃可以用重做日志(Redo Log)进行恢复,从而实现持久性。
与回滚日志记录数据的逻辑修改不同,重做日志记录的是数据页的物理修改。
MVCC多版本并发控制(Multi-Version Concurrency Control, MVCC)是 MySQL 的 InnoDB 存储引擎实现隔离级别的一种具体方式,用于实现提交读和可重复读这两种隔离级别。
底层实现原理:
MVCC 的实现原理主要依赖于:记录中的三个隐藏字段、Undo Log、ReadView、快照读&当前读。
隐藏字段:每行记录处理我们自定义的字段外,还有数据库隐式定义的DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID 等字段
参考官网:
https://dev.mysql.com/doc/refman/8.0/en/innodb-multi-versioning.html
https://www.bilibili.com/video/BV1864y1976i?spm_id_from=333.999.0.0&vd_source=4512bed9ed20ef639e616ff34000e244
延迟队列主要用于处理需要在将来某个时间点执行的任务。所以我们可以
ZSET(有序集合),ZSET 是 Redis 中的一个数据结构,它允许我们存储带有分数(score)的成员(member)。分数可以用来表示时间戳,从而实现任务的延迟执行。LIST 存储任务,并为每个任务设置一个过期时间。当任务过期时,可以通过一个定时任务来检查并处理这些任务。KEYSPACE EVENTS 监听键的过期事件。当一个键过期时,Redis 会触发一个事件,消费者可以监听这个事件并处理相应的任务。ZSET 方法最为常见且易于实现,适合大多数延迟队列的场景。LIST 和 EXPIRE 方法在某些特定情况下也有其优势,特别是当任务数量较少且需要精确控制过期时间时。KEYSPACE EVENTS 方法则适用于需要实时处理过期任务的场景。
ZSET的实现步骤:
ZADD delay_queue <timestamp> <task_id>
ZSET 中取出所有已到期的任务(即分数小于等于当前时间戳的任务)。ZRANGEBYSCORE delay_queue -inf now
ZSET 中删除该任务。ZREM delay_queue <task_id>
ZSET 是 Redis 中的一个数据结构,它允许我们存储带有分数(score)的成员(member),其中分数是用来排序的。底层数据结构由两个部分组成:
1、插入和删除操作简单:跳表的插入和删除操作相对简单,不需要像平衡二叉树那样进行复杂的旋转操作来维持平衡。这使得跳表在实现和维护上更加容易,同时也减少了代码的复杂性和潜在的错误。
2、并发性能好:跳表在并发环境下的性能较好。由于跳表的多层结构,可以在不同层上并行进行插入和删除操作,而不会像平衡二叉树那样需要频繁地进行全局性的调整。这使得跳表在高并发场景下具有更好的性能。
3、实现成本低:跳表的实现相对简单,代码量较少,容易理解和调试;衡二叉树的实现较为复杂,需要处理各种旋转操作,代码量较多,调试难度较大。
注意:
跳表在平均情况下的时间复杂度与平衡二叉树相当,均为 O(log N),但在最坏情况下,跳表的时间复杂度为 O(N),而平衡二叉树的时间复杂度仍然保持在 O(log N)。然而,在实际应用中,跳表的性能通常非常接近 O(log N),并且在大多数情况下表现良好。
虽然跳表在最坏情况下可能会占用更多的内存(因为每个节点可能有多个指针),但在实际应用中,跳表的内存开销通常是可以接受的。相比之下,平衡二叉树的每个节点只需要两个指针(左子节点和右子节点),但在插入和删除时需要进行额外的旋转操作,这些操作可能会导致更多的内存分配和释放。
(1)查询缓存:缓存最近的查询结果,以减少重复查询的开销。
(2)过滤缓存:缓存过滤条件的结果,以加快过滤操作。
(3)字段数据缓存:缓存字段数据,以加快聚合和排序操作。
(1)分段索引:将索引分成多个段,每个段独立管理,便于并行处理和优化。
(2)合并策略:定期合并小段索引,减少索引文件的数量,提高搜索性能。
(3)压缩:对索引数据进行压缩,减少磁盘 I/O 开销。
倒排索引将文档中的每个词项映射到包含该词项的文档列表。
在了解倒排索引的实现原理之前,我们有先看下倒排索引的构建过程是什么?
倒排索引的实现原理由三部分组成:词项索引(Term Index)、词项字典(Term Dictionary)和倒排列表(Posting List)。
在实际生产场景中,比如 ES 最常用的日志分析,日志内容进行分词之后,可以得到多少的 term?---海量的Term,那么如何快速的在海量 term 中查询到对应的 term 呢?遍历一遍显然是不现实的。于是乎就有了词项字典(Term Dictionary)。
词项字典存储所有唯一的词项及其元数据。每个词项通常包含以下信息:
词项字典通常使用一种高效的数据结构来实现,如 B+树 或 Trie(前缀树),以支持快速的查找和插入操作。
现在词项字典(Term Dictionary)应该放在哪里?有人肯定想说放在内存里面吧?磁盘 io 那么慢。
但是如果把整个 term dictionary 放在内存里面会有什么后果呢?
内存很容易撑爆...ES 默认可是会对全部 text 字段进行索引,必然会消耗巨大的内存,为此 ES 针对索引进行了深度的优化。在保证执行效率的同时,尽量缩减内存空间的占用。于是乎就有了词项索引(Term Index)。
词项索引从数据结构上分类算是一个“Trie(前缀树)”,也就是我们常说的字典树,专门处理字符串匹配的数据结构,用来解决在一组字符串集合中快速查找某个字符串的问题。
这棵树不会包含所有的 term,它包含的是 Term 的一些前缀(这也是字典树的使用场景,公共前缀)。通过 term index 可以快速地定位到 term dictionary 的某个 offset,然后从这个位置再往后顺序查找。
Lucene 在这里还做了两点优化,一是 term dictionary 在磁盘上面是分 block 保存的,一个 block 内部利用公共前缀压缩,比如都是 Ab 开头的单词就可以把 Ab 省去。二是 term index 在内存中是以 FST(finite state transducers)的数据结构保存的。
倒排列表存储包含特定词项的文档列表及其相关信息。每个倒排列表条目通常包含以下信息:
倒排列表通常使用 数组 来实现,以支持高效的遍历和访问。
实际上倒排列表中还用到了一些优化技术,以减少存储空间和磁盘IO。如:对倒排列表进行增量编码方式(FOR)进行压缩,减少存储空间和 I/O 开销;跳表(Skip List):在倒排列表中添加跳表,加快范围查询的速度;缓存:缓存常用的词项和倒排列表,减少磁盘 I/O 次数。
以上,点亮【赞与在看】让我们心中充满力量、披荆斩棘、不惧未来!
【推荐阅读】
关于作者:一位热爱技术,并在职场与自媒体间探索的实践者,希望通过分享个人经验和见解,帮助更多人实现自我成长和价值。
原文作者:皇子谈技术;如有侵权,请联系管理员删除。