2023-09-12 06:24:29
针对美团二面中涉及的Spring Boot、并发控制、Spring容器管理、数据库优化及算法场景等问题,以下是系统性解答:
一、贪吃蛇游戏并发问题解决方案乐观锁:通过版本号(Version)控制,更新时检查版本是否匹配。例如:
UPDATE fruit SET count = count-1, version = version+1 WHERE id = ? AND version = ?若影响行数为0,则重试或报错。悲观锁:直接锁定果子记录,阻塞其他线程操作。例如:
SELECT * FROM fruit WHERE id = ? FOR UPDATE;Synchronized:对共享资源(如果子列表)加锁,但可能降低并发性能。
CAS(Compare-And-Swap):原子操作更新果子数量,适用于低竞争场景。
自旋锁:通过循环尝试获取锁,减少线程阻塞开销,但需设置超时机制。
注解与AOP:
使用@Transactional保证数据库操作原子性。
通过AOP切面统一处理并发异常(如乐观锁冲突时的重试逻辑)。
Key:Bean的名称或ID(唯一标识)。
Value:BeanDefinition对象,包含类名、作用域、依赖注入信息等。
通过@Component、@Service等注解将类声明为Bean。
使用@Autowired或构造函数注入依赖,Spring容器自动装配。
对于集合类型(如List<Service>),可通过@Autowired private List<MyService> services;注入所有符合类型的Bean。
用于存储线程私有变量,避免共享变量竞争。
典型场景:数据库连接管理、用户会话信息传递。
查询bc:若索引为(a,b,c),则bc无法直接利用索引(缺少最左前缀a)。
查询ba:同样无法利用索引,因b非索引第一列。
优化建议:
调整索引顺序为(b,a,c)以支持ba查询。
或创建单独索引(b,c)支持bc查询。
索引层级:索引存储在B+树结构中,叶子节点存储数据或主键,非叶子节点存储索引键。
原子性(Atomicity):事务不可分割,要么全部成功,要么全部回滚。
一致性(Consistency):事务执行前后数据状态一致。
隔离性(Isolation):并发事务互不干扰。
持久性(Durability):事务提交后数据永久保存。
脏读:读取未提交数据。解决方案:设置隔离级别为READ COMMITTED或更高。
幻读:同一事务内多次查询返回不同结果(其他事务插入新数据)。解决方案:
使用SERIALIZABLE隔离级别。
通过SELECT ... FOR UPDATE加锁。
使用间隙锁(Gap Lock)防止幻读(InnoDB引擎支持)。
方法:使用哈希表记录已出现元素,遍历链表时跳过重复节点。
代码示例:
public ListNode deleteDuplicates(ListNode head) { Set<Integer> seen = new HashSet<>(); ListNode curr = head, prev = null; while (curr != null) { if (seen.contains(curr.val)) { prev.next = curr.next; } else { seen.add(curr.val); prev = curr; } curr = curr.next; } return head;}高并发扣减库存:结合乐观锁与重试机制,或使用分布式锁(如Redis Redlock)。
分布式ID生成:采用雪花算法(Snowflake)或数据库自增序列。
缓存穿透/雪崩:
穿透:缓存空值或使用布隆过滤器。
雪崩:设置随机过期时间,或使用多级缓存。
@Resource:按名称注入(默认)或类型注入。
@Component:通用Bean声明,@Service、@Repository为其特化。
@Scope:指定Bean作用域(如singleton、prototype)。
日志记录:通过切面统一打印方法入参、耗时。
权限校验:在方法执行前检查用户权限。
事务管理:通过@Transactional自动开启/提交事务。
总结:面试中需结合具体场景选择技术方案,例如并发控制优先乐观锁(低冲突)或悲观锁(高冲突),索引优化需分析查询模式。同时,清晰阐述Spring容器管理原理与MySQL事务机制能体现深度理解。