学而思索面经分享
面试整理(3年工作经验)
第一家 跨境电商 自研
1.做一个自我介绍
2.上一个公司为什么离职?
3.场景题,跨境电商,一台jvm,一个进程,单体应用,只有一台mysql数据库,我像做一个秒杀活动,秒杀的商品1000份,
要求:1.不能加锁 2.不能把所有请求打到mysql上面去,用户10多w,QPS有1w个,怎么解决超卖问题,不能明面上加锁 (不知道什么好答案能让面试官满意)
1.预先加载商品库存到内存中:在秒杀活动开始之前,将商品的库存数量提前加载到内存中,以减少对数据库的频繁查询。可以使用缓存技术(如Redis)将商品库存信息存储在内存中,并在更新库存时保持一致性。
2.使用乐观锁机制:在数据库中的商品表中增加一个版本号字段(version),每次更新库存时需要同时比较版本号。当发起秒杀请求时,先读取当前版本号,然后执行更新操作时,再次校验版本号是否一致,如果一致才进行库存更新。
3.使用队列进行异步处理:将秒杀请求放入消息队列中进行异步处理,避免直接打到数据库上去。消费者从队列中获取请求,处理库存更新操作,并返回秒杀结果给用户。
4.实现限流控制:通过在应用层面设置限流策略,控制用户请求的并发量,防止过多的请求同时访问系统,导致系统负载过高。可以使用令牌桶算法或漏桶算法来进行限流控制。
5.支付的时候,让前端做一个答题,滑动验证,减少并发的数量级。
4.滑动窗口的限流算法,桶(漏桶限流算法),令牌桶算法的区别
1.滑动窗口的限流算法:
滑动窗口算法通过维护一个固定大小的时间窗口,在这个时间窗口内对请求进行计数。只有在时间窗口内请求的计数未超过设定的阈值时,请求才会被允许通过,否则请求将被拒绝。
该算法简单易懂,适用于对请求进行简单的时间窗口内的限流控制。
2.桶(漏桶)限流算法:
桶(漏桶)限流算法是一种固定容量的桶,按照固定速率出水。对于请求来说,如果桶中有空间,则请求被加入到桶中;如果桶已满,则请求被拒绝。
该算法可以平滑处理突发请求,控制请求的发送速率,适合对请求进行速率限制。
漏桶算法有一个缺点:当系统在短时间内有大流量进来,漏桶算法处理不了。
3.令牌桶算法:
令牌桶算法是另一种固定容量的桶,但与桶(漏桶)限流算法不同,令牌桶算法以固定的速率往桶中添加令牌。每当有一个请求到达时,需要消耗一个令牌,只有在有足够令牌时,请求才会被允许通过。
该算法可以精确控制请求的发送速率,并且可以应对突发流量。
令牌桶算法的几种情况:
请求速度大于令牌的生成速度:那么桶中的令牌会被取完,后续再进来的请求,由于拿不到令牌会被限流。
请求速度等于令牌的生成速度:那么此时系统处于平稳状态。
请求速度小于令牌的生成速度:那么此时系统的访问量远远低于系统的并发能力,请求可以被正常处理。
令牌桶算法,由于只有一个桶的存在,可以处理短时间大流量的场景,这是令牌桶和漏桶的一个区别。
5.了解ThreadLocal不
ThreadLocal 是 Java 中的一个类,它提供了线程局部变量的功能。简单来说,ThreadLocal 可以让每个线程都拥有自己独立的变量副本,互不干扰。这在多线程并发编程中非常有用,特别是在需要在每个线程中保持一些上下文信息或状态时。
6.ThreadLocal的原理
底层是一个Map,key是ThreadLocal的线程id,value 是对应线程的局部变量值
7.spring里面的@Transaction在什么情况下会失效?
1.未被 Spring 托管的类:如果一个类没有被 Spring 托管(即没有被 Spring 管理),那么在该类中使用 @Transactional 注解将不会生效。因为 Spring 无法拦截和代理未被 Spring 管理的类中的方法。
2.异常捕获:如果在事务方法内部捕获了异常并处理了而没有抛出,那么事务可能不会回滚。通常情况下,Spring 的事务管理是基于抛出异常来触发事务回滚的,如果异常被捕获并处理了,事务可能不会回滚。
3.在同一个类中调用另一个带有 @Transactional 注解的方法:当在同一个类中的一个带有 @Transactional 注解的方法调用另一个带有 @Transactional 注解的方法时,事务可能会失效。这是因为 Spring 默认使用基于代理的 AOP 来实现事务管理,对于同一个类中的方法调用并不会经过代理,导致事务注解不生效。
4.线程问题:如果在一个未被 Spring 托管的线程中调用带有 @Transactional 注解的方法,事务也可能失效。因为 Spring 事务管理是基于当前线程的事务上下文进行管理的,如果线程不受 Spring 管理,事务可能无法正确传播。
5.事务传播机制设置错误:如果在使用 @Transactional 注解时设置了错误的事务传播机制,可能会导致事务失效。比如某个方法使用了 REQUIRED 的传播机制,但实际情况下应该使用 REQUIRES_NEW 才能正确管理事务
8.Spring中的动态代理是什么?
在 Spring 中,动态代理是一种 AOP(面向切面编程)的实现方式,它允许在运行时为目标对象生成代理对象,从而实现对目标对象方法的拦截和增强。动态代理通常用于实现横切关注点(cross-cutting concerns),比如事务管理、日志记录、性能监控等功能。
在 Spring 中,动态代理主要有两种实现方式:
基于 JDK 动态代理:JDK 动态代理是Java提供的一种动态代理机制,它要求被代理的类必须实现一个接口。Spring 使用 JDK 动态代理来生成代理对象,当业务类实现了接口时,Spring 就可以通过 JDK 动态代理生成实现这些接口的代理对象。在代理对象的方法调用前后,可以插入相应的逻辑进行增强处理。
基于 CGLIB 动态代理:CGLIB 是一个强大的、高性能的代码生成库,它可以在运行时动态生成指定类的子类,并重写其中的方法实现代理功能。相比于 JDK 动态代理,CGLIB 可以代理没有实现接口的类,而且通常情况下 CGLIB 动态代理生成的代理对象效率更高。
Spring 在使用动态代理时会根据被代理对象是否实现了接口来选择使用 JDK 动态代理还是 CGLIB 动态代理。如果目标对象实现了接口,Spring 会使用 JDK 动态代理;如果目标对象没有实现接口,Spring 会使用 CGLIB 动态代理。
通过动态代理,Spring 能够在不修改原有代码的情况下,通过增加针对特定方法的拦截器(Interceptor)等手段,实现诸如日志记录、性能监控、事务管理等横切关注点的功能,从而提高了系统的可维护性和扩展性。
9.poxy和cglib的区别是什么?
CGLIB 动态代理和 JDK 动态代理(也称为 Proxy 动态代理)是 Spring AOP 中两种常用的代理实现方式,它们之间有一些区别:
基于类和接口:
JDK 动态代理只能代理实现了接口的类,它通过反射机制来创建一个接口的实现类作为代理。
CGLIB 动态代理则可以代理没有实现接口的类,它通过生成目标类的子类来实现代理。
性能:
JDK 动态代理在创建代理对象时性能相对较低,因为它需要通过反射调用来实现代理。
CGLIB 动态代理在创建代理对象时性能较高,因为它是通过生成字节码的方式来实现代理,避免了反射调用。
代码侵入性:
JDK 动态代理要求目标对象必须实现接口,这就要求目标类必须修改以实现接口,可能会导致代码侵入性增加。
CGLIB 动态代理不要求目标对象实现接口,可以直接代理目标类,减少了代码侵入性。
性能优化:
JDK 动态代理由于使用反射,无法对 final 方法进行代理,而 CGLIB 可以代理 final 方法。
JDK 动态代理在调用被代理方法时,会经过一层方法调用,而 CGLIB 则直接调用目标对象的方法。
总体而言,JDK 动态代理适合代理接口的情况,对于没有实现接口的类,则需要使用 CGLIB 动态代理。在性能要求较高或需要代理 final 方法的情况下,CGLIB 动态代理更为合适。在选择代理方式时,可以根据具体需求和场景来决定使用 JDK 动态代理还是 CGLIB 动态代理。
10.支付接口 ,聚合支付 ,掉用不同的支付接口 , 用attent来传参(比如微信,支付宝,国外平台的特有标识),如何保证在不更改太多的代码,达到实现效果?(不确定是面试官想要的答案不)
1.我的思路是通过面向接口编程,调用支付后,先经过某个接口(公共支付),
找出传参属于哪一种支付类型,再到对应得实现类里面去处理对应的逻辑。
2.也可以使用到工厂设计模式,支付方式定义一个工厂类,
其它各个渠道得,去实现这个工厂类,让它进行处理对应的逻辑。
11.SpringBoot的全局异常处理做过没得?
可以自己去定义和创建对应的异常处理类。给异常统一抛出一个返回类
12.微信支付是原生还是整合?
聚合 payment-spring-boot-starter
未能定位到原文的划线
企业级Agent工作流编排项目PaiFlow
Vibe Coding版本的PaiAgent
派聪明RAG AI知识库Java版本+Go版本
微服务 PmHub、技术派、MYDB
求职派JobClaw(OpenClaw/Hermes架构
PaiCLI(类似Claude Code的Agent
派简历(代码已完成)
等实战项目。
1. 微信扫右侧的优惠券加入知识星球
2. 解锁星球的实战项目教程和源码: 项目源码+教程获取
真诚点赞 诚不我欺
回复