Java面试: 通过一个985硕士同学的简历看一下项目有哪些问题(一)?
最近和一个985硕士同学聊项目,因为他们教研室主要是学术为主,加上没实习过,所以在**买了2个项目,可以看看这些号称在字节、阿里等工作过的程序员卖给学生的项目有哪些问题?
项目: 一个已小说为背景的业务
第一个问题: 真实的项目不可能开发这么多的模块。 这个项目又有推荐,检索,排行榜,秒杀等等模块。 而且小说推荐、排行榜、秒杀是流量最高,最复杂的业务,而该同学主要内容说的难点似乎一点都不难,该难的没难,不该难得难了。
如果你在小公司上班或者实习,那么你确实有可能负责这么多模块的开发。但是一没有用户,二没有流量的公司,任何需求都不会有难点的。那面试官和你沟通什么呢? 一眼假的项目,面试官和你沟通数据库的增删改查吗?
如果你在一个差不多规模的公司工作或者实习,研发有几百甚至几万人。那么这么多人维护的项目,你一个人几乎开发完了,肯定不合理的。又或者你确实做了这么多模块,排行榜,优惠券等也是流量最高最复杂的项目,里面肯定是有难点的,但是你和面试官沟通的时候,你却梳理不清楚里面的难点。
我在美团工作期间有带过一个实习生,毕业后,他进入了一家一线互联网公司工作,做营销业务。 工作快2年,最近开始找工作,投递了京东和拼多多,面试期间,几乎都是围绕着项目。所以,不管是校招还是社招,如果你想找一个好工作,需要准备1~3个真实的企业级开发项目,并且这些项目真的有难点和你的思考点。你项目要是没有干货,又没有在大厂工作或者实习过,已现在的结业环境,你几乎不太可能进大公司了。
第二个问题:该同学第一个任务,做登录和权限关联的工作。 真实的业务:你不需要关注用户是否登录或者是否有权限。
已该同学的项目:小说**项目为例:
小说排行榜,小说评论等模块都需要判断权限,那每一个模块都要关注权限或者用户是否登录。 比如你们公司有100个模块,那么重复的逻辑做了100次, 以后权限或者登录功能发生变更时,那这100个模块,都要兼容这个逻辑,明显是不合理的。
那么一个更合理的解决方案是,在网关层做这一部分逻辑。网关层判断这个用户是否登录或者是否有权限。 没有权限直接返回错误码,有权限后,再将流量转发到对应的业务系统。那么业务系统就不需要关注用户是否登录或者是否有权限。
第三个问题: 该同学第二个任务,使用乐观锁去更新小说库存,库存数量作为版本号。
小建议: 项目没难度,就没难度,真别硬拼难度了。 就算优化也要优化的有水平,这种乐观锁更新库存,有点掉价。
看一下乐观锁更新库存有哪些问题?
问题出现的背景:
用户A,在T0时刻购买书本A,该商品库存1,T1时刻计算需要将书本库存更新成0,在T2时刻更新该书本库存,数据库该书本库存数量为0。
问题: 更新逻辑为先查询商品库存,计算,最后更新库存。 查询到更新有时间差(时间差T2-T0),这个时间差内,如果有其他用户购买书本A,同样的,查询出该书本库存数量为1,最后更新结果库存数量也是0。
库存数量为1,但是却有2个用户抢购到了该书籍,那怎么发货呢?
所以该同学想到了如下解决方案: 使用乐观锁,库存数量作为版本号:
将代码改成如下形式,其主要逻辑为:
将代码改成如下形式,其主要逻辑为:
- 查询该书本库存,查询SQL为 select * from merchant_store_detail where book_id = ? 或者 select * from merchant_store_detail where id = ? 查询出该书籍库存1
2.在内存计算该商品库存;
3.更新数据库该书本库存,更新SQL由:update merchant_store set store_num = ? where book_id = ?
变成:update merchant_store set store_num = ? where book_id = ?and store_num = 1;
4.更新失败的线程,一直重试,直到更新成功。
用户A,在T0时刻购买书本A,该商品库存1,T1时刻计算需要将书本库存更新成0,在T2时刻更新该书本库存,数据库该书本库存数量为0。这个时间差内(T2-T0),如果有其他用户购买书本A,查询出商品库存为1,但是T2时刻,用户A已经将该库存更新成0,T3时刻,其他用户线程更新数据库时:update merchant_store set store_num = 0 where book_id = ?
and store_num = 1; store_num = 1不满足条件,更新失败。 则该用户线程重试。
咋一看,这个解决方案还可以,不加锁就可以保证书本数量更新成功。
但是细想一下,这个场景真的合适使用乐观锁吗?用户下单流程是最核心功能:
如果流量低,你们的服务使用一台服务器,一个进程下完全可以使用synchronized锁,锁当前书籍id。synchronized锁在流量低的应用,性能还是非常好的,那么就没有必要使用乐观锁。 而且你们思考一下,乐观锁的实现真的难吗? 大量的博客或者视频都讲解过该知识。
如果流量高,更新库存又是写操作。 乐观锁的使用场景是读多写少,那么线程在更新数据时,因为几乎没有线程更新数据,那么当前线程可以有很大概率更新成功。 但是写操作多的场景,很多用户线程在更新数据,那么当前线程有很大概率更新失败。大量线程写失败异常对系统造成的影响比锁还要大。而且流量高时,乐观锁会将打到数据层的流量放大。用户A线程在T0时刻读库存,T2时刻更新库存,在T0~T2时间段内,其他用户线程更新库存时,更新失败,然后重试。假设每秒有10个用户抢购该书籍,那么9个失败,1个成功。 下一秒又有10个用户抢购该书籍,也就是此时有19(10个新用户 + 9个更新失败的用户)个线程在做相同的逻辑,线程不断重试,流量又不断过来,这个流量会不断累积。 此时也只考虑了一个书籍的抢购,抢购的书籍也多,失败的线程又在不断重试,打到数据库的流量不断升高(因为大量的线程在重试),会将数据库打挂。
解决方案:
流量高的应用,如何合理的更新库存。 需要引入Redis,MQ,数据库行锁。 知识点很多,没有办法在短时间讲解清楚,这里就不叙述了。
扩展: 该同学乐观锁的实现,使用库存数量作为版本号。 但是库存数量不太适合作为版本号的,因为会产生ABA问题,你们可以思考一下,为什么会产生ABA问题。
所以一个项目有难点就是有难点,而不是一个你认为的难点。因为逻辑讲不通。这种难点和设计写到简历上,有点失水准。
未完待续~
#java面试题##java##我的失利项目复盘##简历中的项目经历要怎么写#