Bootstrap

全栈(Java+vue)实习面试题(含答案)

        在广州一个小公司(BOSS标注是0-20人,薪资2-3k),直接面试没有笔试,一开始就直接拿着简历问,也没有自我介绍,问题是结合场景题和八股文、基础。废话不多说,直接分享面试题目个大家做参考。

1、能讲一下IOC吗?

IOC就是控制反转,这是一种设计模式,核心思想是将对象的创建、依赖注入和生命周期管理交给IOC容器负责。在传统的编码方式中,我们一般需要在类中手动创建依赖对象,通过硬编码方式来控制对象的实例化和管理,而在Spring中,Bean以及对象之间的依赖关系都交给IOC容器负责,降低了代码之间的耦合度,也提高了系统的灵活性;

spring中主要通过XML配置和注解配置的两种方式实现。

2、数据库三范式能说一下吗?

数据库的三范式是关系型数据库设计的基本原则,旨在减少数据冗余、提高数据的一致性,并确保数据依赖的合理性;

第一范式:字段具有原子性,就是每个字段不能再拆分。比如联系方式应该拆分为电话和地址两个独立的字段;

第二范式:在满足第一范式的基础上,消除部分依赖,就是非主键字段必须完全依赖主键中的各个字段(表中使用的是复合主键,主键包含多个字段)。比如订单明细表的主键是订单ID+产品ID,字段客户姓名仅依赖订单ID,可以将客户姓名移到以订单ID为主键的订单表中;

第三范式:在满足第一、二范式的基础上,消除传递依赖,就是非主键字段不能依赖其他非主键字段。比如学生表包含学号(主键)、学院、学院电话,其中学院电话依赖学院,而学院依赖学号,应拆分为学生表(学号、学院)和学院表(学院、学院电话)

这种规则约束减少了冗余、避免了跟新异常,但过度范式化可能导致多表关联查询、降低性能;

3、数据库的优化问题?

(1)表设计优化

  1. 选择合适的数据类型,尽量使用最小的数据类型(比如使用INT替代BIGINT,使用CHAR替代VARCHAR)来减少存储和查询成本;
  2. 分区表:对于数据量极大的表可以考虑分区表,将表按某些规则分割成多个小表,提高查询效率;
  3. 主从复制、读写分离:如果数据库读的操作比较多,为了避免写操作所造成的性能影响,可以采用读写分离的架构;

(2)索引优化:

  1. 创建适当的索引,避免过多的索引,查照索引的创建原则;
  2. 覆盖索引:使用索引覆盖查询,避免回表,调高效率;

(3)SQL语句优化:

  1. 尽量明确指定需要的列,避免使用SELECT *,以减少不必要的数据传输;
  2. SQL语句要避免造成索引失效的写法;
  3. 尽量用union all 替代 union ,union多了一次过滤,效率较低;
  4. 避免子查询,特别是当子查询返回大量数据时,可以考虑JOIN或WITH子句替代

索引创建原则和失效场景看这篇八股文:

https://blog.csdn.net/weixin_73144915/article/details/145535602?spm=1001.2014.3001.5501

4、知道多态吗,解释一下?

多态指同一个操作作用于不同对象时,可以有不同的实现方式。核心目的是提高代码的灵活性和可扩展性;多态的两种形式如下:

1、编译时多态(静态多态),实现方法重载,在编译时根据参数类型和个数确定调用哪个方法;

2、运行时多态(动态多态),通过接口/继承和方法重写来实行,在运行时根据对象的实际类型决定调用哪个方法;

5、hashMap和hashTable的区别?

HashMap和Hashtable都是Java中用于存储键值对的哈希表类,区别如下:

(1)线程安全:HashMap不是线程安全的,如果多个线程并发访问HahsMap,并且至少有一个线程做了修改,他必须通过外部同步来保证线程安全,否则可能会导致数据不一致的情况;而Hashtable是线程安全的,他的方法都被synchronized修饰,可以在多线程环境下安全的被访问;

(2)性能:HashMap性能通常优于Hashtable,特别是在单线程环境下;而Hashtable由于方法上都有同步锁,性能较差;

(3)Null值:HashMap允许一个null值(键唯一性)和多个null值;而Hashtable不允许出现null键或null值。

6、SpringMVC的核心是什么?

SpringMVC的核心是基于前端控制器模式的请求驱动设计,将前端控制器作为中央调度器,拦截请求将请求分发给对应的处理器,并协调视图解析、数据绑定等组件完成全流程处理。其核心设计理念是解耦、模块化、可扩展。核心流程如下:

1.发送请求:用户发送请求,被前端控制器拦截;

2.映射处理器:处理器映射器根据URL找到对应的Controller层和方法;

3.调用控制器:Controller执行业务逻辑,返回ModelAndView数据;

4.解析视图:视图解析器将视图名称转化为具体视图(如HTML页面);

5.渲染视图:将模型数据填充到视图中,生成最终响应给用户;

7、怎么解决超卖问题?

解决超卖问题的核心在于保证库存扣减的原子性和一致性,尤其是在高并发场景下。以下是分层的解决方案,涵盖技术实现和业务逻辑优化:


一、技术层面解决方案

1. 数据库锁机制

  • 悲观锁(Pessimistic Lock)
    在事务中通过 SELECT ... FOR UPDATE 锁定库存记录,防止其他事务修改。

BEGIN;
SELECT stock FROM products WHERE id=1 FOR UPDATE;
UPDATE products SET stock = stock - 1 WHERE id=1;
COMMIT;
  • 缺点:性能较差,适用于低并发场景。

  • 乐观锁(Optimistic Lock)
    通过版本号或时间戳控制并发,仅当库存未被修改时才扣减。

UPDATE products 
SET stock = stock - 1, version = version + 1 
WHERE id=1 AND version = {current_version} AND stock > 0;
  • 优点:性能高,适合高并发;缺点:需重试逻辑(如失败后提示用户重新下单)。

2. 分布式锁(Redis/ZooKeeper)

  • 使用 Redis 的 SETNX 或 RedLock 算法,确保同一时间只有一个请求能操作库存。
    示例(Redis + Lua脚本保证原子性):

local key = "product_1_stock"
local decrement = 1
local stock = tonumber(redis.call('GET', key))
if stock >= decrement then
    redis.call('DECRBY', key, decrement)
    return 1  -- 扣减成功
else
    return 0  -- 库存不足
end

适用场景:分布式系统,需配合数据库最终一致性。

3. 缓存预扣库存(Redis + 异步队列)

步骤

  1. 将库存预热到 Redis 中。

  2. 用户下单时,先通过 DECR 扣减 Redis 库存。

  3. 若扣减成功,将订单信息发送到消息队列(如 Kafka、RabbitMQ),异步更新数据库。

  4. 若最终数据库更新失败,需回滚 Redis 库存(如通过 TTL 自动过期或补偿事务)。

优点:扛住瞬时高并发;缺点:需处理缓存与数据库的数据一致性。

8、Mybatis中XML和注解你是怎么使用的? 

配合着使用,一些简单的SQL语句可以直接用注解来写,而复杂SQL、联表查询的用XML来写

9.如果利用用户ID恶意访问接口,怎么解决?

1. 采用 Token 进行身份验证

  • 使用 JWT(JSON Web Token) 或 Session 机制 进行身份认证,确保用户必须先登录后才能访问接口。
  • Token 绑定用户身份,服务器通过 Token 解析出用户 ID,而不是让前端传递用户 ID。

2. 避免前端传递用户 ID

  • 服务器根据 Token 自动获取当前用户 ID,而不是让前端传递 userId 参数。
  • 示例
@GetMapping("/user/profile")
public ResponseEntity<UserProfile> getUserProfile(@RequestAttribute("userId") Long userId) {
    UserProfile profile = userService.getProfileById(userId);
    return ResponseEntity.ok(profile);
}

这里 userId 是从 JWT 解析出来的,而不是从前端传递的参数。 

3. 进行权限校验

  • 后端校验数据归属权,即使用户传递 userId,也要检查该 userId 是否与当前登录用户匹配。
  • 示例(Spring Boot 权限校验):
@GetMapping("/user/orders")
public ResponseEntity<List<Order>> getUserOrders(@RequestParam Long userId, @RequestAttribute("userId") Long currentUserId) {
    if (!userId.equals(currentUserId)) {
        throw new AccessDeniedException("非法访问");
    }
    return ResponseEntity.ok(orderService.getOrdersByUserId(userId));
}

这里 currentUserId 是从 Token 解析出来的,确保用户不能查询别人的订单。

4. 限制请求频率(防止暴力攻击)

  • 使用 Rate Limiting(限流)机制,比如:
    • Redis + 滑动窗口 进行限流
    • Nginx 限流
    • 使用 Spring Boot 的 Bucket4jGuava RateLimiter
  • 示例(Spring Boot 限流):
@RateLimiter(name = "user-api", fallbackMethod = "limitExceeded")
@GetMapping("/user/data")
public ResponseEntity<?> getUserData() {
    return ResponseEntity.ok("数据获取成功");
}

public ResponseEntity<String> limitExceeded(Exception e) {
    return ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS).body("请求过于频繁,请稍后再试");
}

;