大家好,我是二哥呀。
不得不感慨,生得早不如生的巧,看完 25 届京东的秋招薪资,很多 23 届、24 届的小伙伴开始默默留下了眼泪。
MD,早知道晚生两年了。 CA,早知道延毕一年了。 WOQU,早知道考研赌一把了。
这还有王法吗?
明明 24 届只有 16 薪,到了 25 届,直接 19 薪,这意味着什么,如果 base 是 23k,意味着一年多拿了 23k*3=6.9 万啊,年终奖都有了。
关键是今年京东的 base 还高的离谱,有 985 本的同学说开到了 35k 的 base(连 HR 都说是今年最高的一个)。
有同学就怀疑了,京东开这么高的 base,还是 19 薪,真的能拿满吗?
现在不好说啊。
星球里有球友反馈说,HR 说能拿满(🤣)。我只能说有待观察,毕竟 19 薪也是京东头一遭,必须得等 25 届入职工作一年以后才有结论。
互联网其实就是这样,公司发展的好,老板又大气,肯定是愿意高薪招纳人才的,反正老板的钱又花不完,给兄弟们分点也是合情合理。
况且,东哥今年很早就承诺要加薪,这个我 9 月份就给大家同步过:京东加薪20%,同时扩招2000人
所以,听劝选择京东的小伙伴今年都是幸运儿。
再者说,京东在业界有“京多多”的称号,早上 9 点到公司,中饭和午休据说只有一个小时,晚上加班也是离 10 点不差几个小时,甚至更晚(笑)
强度这么大,薪资再上不去,谁受的得了。
往年京东是不抢人的,年龄结构在互联网算大的,薪资待遇也都不是一线梯队的水平,今年东哥可能想明白了,向字节、拼多多看齐。
我从用户的角度说一点感受哈。
前段时间,淘宝不是接入了微信支付嘛,我就想体验一下,买了一本《观止》,写微软 NT 的,这本书绝版了,所以只能买二手的。
淘宝标明 9 成新,结果到手,1 成新都不到,真不夸张,差的要命。于是就选择了退货,结果运费 15 元,我滴妈呀!书才 24 块钱,等于说我用 15 元买了个寂寞,愤愤不平地把淘宝都卸载了。😄
当时还在文章留言区吐槽过:有小伙伴就留言说,还得是京东啊。
其实一家公司发展的好不好,从用户的角度能很明显地感受到。
京东不是搞了个 PLUS 会员嘛,有一段时间每个月只送 6 张运费券,额外赠送的 100 元优惠券,还要定时去领取才能领得到,搞得很恶心,所以有段时间我都改用拼多多了。
大气一点,别搞的那么恶心,用户是有判断力的。
就目前京东的做法来看,我觉得是比较深得人心的,25 届我钱给够,来不来自己做选择。
好接下来,我们就以Java 面试指南中收录的同学 5 京东后端技术一面为例来看看,后面冲京东的话应该准备哪些内容。
1、二哥的 Linux 速查备忘手册.pdf 下载 2、三分恶面渣逆袭在线版:https://javabetter.cn/sidebar/sanfene/nixi.html
同学 5 京东后端技术一面
简单介绍一下项目
PmHub 是一套基于 SpringCloud & LLM 的微服务智能项目管理系统,采用时下企业最热门的技术框架,如 SpringCloud-Gateway、Nacos、Sentinel 等,包括认证、流程、项目管理、用户、网关等服务。
建表考虑哪些问题
在建表的时候,首先可以考虑表是否符合数据库范式,也就是确保字段不可再分,消除非主键依赖,确保字段仅依赖于主键。
然后在选择字段类型时,尽量选择合适的数据类型。
在字符集上,尽量选择 utf8mb4,这样不仅可以支持中文和英文,还可以支持表情符号等。
当数据量较大时(比如上千万行数据),需要考虑分表。比如订单表,可以采用水平分表的方式来分散存储压力。
建立索引考虑哪些问题
①、选择合适的列作为索引
经常作为查询条件(WHERE 子句)、排序条件(ORDER BY 子句)、分组条件(GROUP BY 子句)的列是建立索引的好选项。 区分度低的字段,例如性别,不要建索引 频繁更新的字段,不要建索引
②、避免过多的索引
因为每个索引都需要占用额外的磁盘空间。 更新表(INSERT、UPDATE、DELETE 操作)的时候,索引都需要被更新。
③、利用前缀索引和索引列的顺序
对于字符串类型的列,可以考虑使用前缀索引来减少索引大小。 在创建联合索引时,应该根据查询条件将最常用的放在前面,遵守最左前缀原则。
索引失效情况
在索引列上使用函数或表达式:索引可能无法使用,因为 MySQL 无法预先计算出函数或表达式的结果。例如: SELECT * FROM table WHERE YEAR(date_column) = 2021
。使用不等于( <>
)或者 NOT 操作符:因为它们会扫描全表。使用 LIKE 语句,但通配符在前面:以“%”或者“_”开头,索引也无法使用。例如: SELECT * FROM table WHERE column LIKE '%abc'
。联合索引,但 WHERE 不满足最左前缀原则,索引无法起效。例如: SELECT * FROM table WHERE column2 = 2
,联合索引为(column1, column2)
。
乐观锁与悲观锁
悲观锁认为它保护的数据是非常敏感的,每时每刻都有可能被改动,一个事务在拿到悲观锁后,其他事务不能对该数据进行修改,直到它提交或回滚后。
MySQL 中的行锁、表锁都是悲观锁。
乐观锁则认为数据的变动不会太频繁。通常通过版本号(version)或者时间戳(timestamp)来实现。
事务拿到数据后,会将数据的版本号也取出来(比如说标记为 v1),当数据变动完想要更新到表中时,会将最新的版本 v2 和 v1 进行对比,如果 v1=v2,说明在数据变动期间,没有其他事务对数据进行修改。
此时,事务提交就会成功,并且 version 会加 1,以此来表明数据已变动。
如果 v1 不等于 v2,说明数据变动期间,数据被其他事务修改了,此时需要通知用户重新操作。
悲观锁是 MySQL 自带的,而乐观锁通常需要开发者自己去实现。
SpringBoot与SpringMVC区别(不会)
Spring MVC 是基于 Spring 框架的一个模块,提供了一种 Model-View-Controller(模型-视图-控制器)的开发模式。
Spring Boot 旨在简化 Spring 应用的配置和部署过程,提供了大量的自动配置选项,以及运行时环境的内嵌 Web 服务器,这样就可以更快速地开发一个 SpringMVC 的 Web 项目。
SpringBoot启动流程(忘了)
Spring Boot 有一个 main 方法的主类,类上标注了 @SpringBootApplication
注解,这是入口类。
当执行 main 方法时,首先会创建一个 SpringApplication 实例,负责管理应用的启动和初始化。
SpringApplication.run()
方法负责 Spring 应用的上下文(ApplicationContext)环境准备,包括:
扫描配置文件,添加依赖项 初始化和加载 Bean 定义 启动内嵌的 Web 容器等
#{}和${}的区别
#{}
是预编译处理,${}
是字符串替换。
①、当使用 #{}
时,MyBatis 会在 SQL 执行之前,将占位符替换为问号 ?
,并使用参数值来替代这些问号。
由于 #{}
使用了预处理,所以能有效防止 SQL 注入,确保参数值在到达数据库之前被正确地处理和转义。
<select id="selectUser" resultType="User">
SELECT * FROM users WHERE id = #{id}
</select>
②、当使用 ${}
时,参数的值会直接替换到 SQL 语句中去,而不会经过预处理。
这就存在 SQL 注入的风险,因为参数值会直接拼接到 SQL 语句中,假如参数值是 1 or 1=1
,那么 SQL 语句就会变成 SELECT * FROM users WHERE id = 1 or 1=1
,这样就会导致查询出所有用户的结果。
${}
通常用于那些不能使用预处理的场合,比如说动态表名、列名、排序等,要提前对参数进行安全性校验。
<select id="selectUsersByOrder" resultType="User">
SELECT * FROM users ORDER BY ${columnName} ASC
</select>
设计模式
在需要控制资源访问,如配置管理、连接池管理时经常使用单例模式。它确保了全局只有一个实例,并提供了一个全局访问点。
在有多种算法或策略可以切换使用的情况下,我会使用策略模式。像技术派实战项目中,我就使用策略模式对接了讯飞星火、OpenAI、智谱 AI 等多家大模型,实现了一个可以自由切换大模型基座的智能助手服务。
策略模式的好处是,不用在代码中写 if/else 判断,而是将不同的 AI 服务封装成不同的策略类,通过工厂模式创建不同的 AI 服务实例,从而实现 AI 服务的动态切换。
后面想添加新的 AI 服务,只需要增加一个新的策略类,不需要修改原有代码,这样就提高了代码的可扩展性。
IOC与AOP
AOP:面向切面编程,是一种编程范式,它的主要作用是将那些与核心业务逻辑无关,但是对多个对象产生影响的公共行为封装起来,如日志记录、性能统计、事务等。
IoC:控制反转,是一种设计思想,它的主要作用是将对象的创建和对象之间的调用过程交给 Spring 容器来管理。
AOP应用场景
我在技术派实战项目中有应用,比如说我利用 AOP 打印了接口的入参和出参日志,以及执行时间,方便后期 bug 溯源和性能的调优。
redis key过期策略
Redis 的 key 过期回收策略主要有两种:惰性删除和定期删除。
当某个键被访问时,如果发现它已经过期,Redis 会立即删除该键,俗称惰性删除。但这也意味着如果一个已过期的键从未被访问,它就不会被删除,会占用额外的内存空间。
那还有一种定期删除策略,即每隔一段时间,Redis 就会随机检查一些键是否过期,如果过期就删除。这种策略可以保证过期键及时被删除,但也会增加 Redis 的 CPU 消耗。
日志框架 日志级别
Spring Boot 默认使用的日志框架是 Logback,日志级别默认为 INFO,这意味着只有级别为 INFO 及以上的日志信息才会被输出。
日志级别从高到低依次为:
ERROR: 记录错误信息 WARN: 记录警告信息 INFO: 记录一般信息 DEBUG: 记录调试信息 TRACE: 记录详细的跟踪信息
让自己讲一下网络
计算机网络是指将多台计算机通过通信设备互联起来,实现资源共享和信息传递的系统。
计算机网络体系结构通过将复杂的网络通信分解成不同的层次,来标准化交互的过程。常见的模型包括 OSI 七层模型、TCP/IP 四层模型和五层体系结构。
OSI 是理论上的网络通信模型,TCP/IP 是实际应用层面上的网络通信模型,五层结构是为了方便理解和记忆。
tcp拥塞控制
流量控制是为了避免发送⽅的数据填满接收⽅的缓存,但并不能控制整个⽹络。
⼀般来说,计算机⽹络会处在⼀个共享的环境。因此也有可能会因为其他主机之间的通信使得⽹络拥堵。
当⽹络出现拥堵时,如果继续发送⼤量数据包,可能会导致数据包延时、丢失等,这时 TCP 就会重传数据,但重传会增加⽹络负担,于是会导致更⼤的延迟以及更多的丢包,就进⼊了恶性循环....
所以,TCP 被设计成了⼀个非常⽆私的协议,当⽹络发送拥塞时,TCP 会⾃我牺牲,降低发送的数据流。
拥塞控制的⽬的就是避免发送⽅的数据填满整个⽹络。
就像是一个水管,不能让太多的水(数据流)流入水管,如果超过水管的承受能力,水管会被撑爆(丢包)。
发送方会维护一个拥塞窗口 cwnd 的变量,调节所要发送数据的量。
项目中学到了那些东西
非常多,比如说:
Gateway 实现自定义网关统一鉴权统计接口调用时间 使用 Redis+Lua 基于令牌桶实现限流 使用 RocketMQ 实现审批消息异步解耦 集成 OpenFeign+Sentinel 实现服务降级和网关流量控制 集成 Redis 分布式锁保障流程状态更新 通过分布式事务 Seata 保证任务审批状态一致性 自定义注解+AOP 实现服务接口鉴权和内部认证 整合 TTL 缓存用户数据 如何用 Docker 容器化部署项目 使用 Skywalking 监控项目性能 采用 Cache Aside 模式保证缓存和数据库一致性
其他题目
hashmap底层与扩容机制 arraylist与linklist
这几个之前出现过的题目,推荐大家直接去看星球嘉宾三分恶的面渣逆袭 https://javabetter.cn/sidebar/sanfene/nixi.html
。
ending
一个人可以走得很快,但一群人才能走得更远。二哥的编程星球已经有 6500 多名球友加入了,如果你也需要一个良好的学习环境,戳链接 🔗 加入我们吧。这是一个 编程学习指南 + Java 项目实战 + LeetCode 刷题 + 简历精修 的私密圈子,你可以阅读星球专栏、向二哥提问、帮你制定学习计划、和球友一起打卡成长。
两个置顶帖「球友必看」和「知识图谱」里已经沉淀了非常多优质的学习资源,相信能帮助你走的更快、更稳、更远。
欢迎点击左下角阅读原文了解二哥的编程星球,这可能是你学习求职路上最有含金量的一次点击。
最后,把二哥的座右铭送给大家:没有什么使我停留——除了目的,纵然岸旁有玫瑰、有绿荫、有宁静的港湾,我是不系之舟。共勉 💪。