
1) 【一句话结论】针对好未来在线课程系统的选课操作,通过REPEATABLE READ隔离级别的事务保障数据一致性,结合乐观锁(版本号机制+重试3次+1-3秒延迟)处理并发冲突,测试用例验证单事务选课数据一致性、并发下无冲突及用户选课数量限制,并评估极端高并发下的性能表现。
2) 【原理/概念讲解】首先讲事务的隔离级别选择——选课场景需避免脏读和不可重复读,因此选择REPEATABLE READ(类比银行转账:确保“扣款”和“入账”同时完成,数据不丢失或重复,保障一致性)。然后讲乐观锁原理:假设数据未被修改,通过版本号/时间戳验证更新,适用于读多写少场景(选课操作)。比如课程表有version字段,选课前读取version,插入记录后更新version,若版本不一致则重试(避免脏更新)。
3) 【对比与适用场景】
| 特性/场景 | 乐观锁 | 悲观锁 |
|---|---|---|
| 定义 | 假设数据未被修改,通过版本号/时间戳验证更新 | 假设数据会被修改,操作前加锁 |
| 代码实现 | 更新时检查版本,失败则重试 | 操作前加锁(如SELECT FOR UPDATE) |
| 适用场景 | 读多写少,冲突概率低(如选课) | 写多读少,冲突概率高(如库存扣减) |
| 注意点 | 可能导致死锁(重试次数过多) | 可能导致性能瓶颈(锁竞争) |
4) 【示例】测试用例设计:
user_id=1,已选课程数=0),课程C1(course_id=101,剩余名额=1,version=1)。course_id=101):
version=1,remain_count=1),插入记录,更新version=2,提交。version=1,remain_count=1),插入记录,更新version=2(失败,版本不一致),重试(随机延迟1-3秒)。course_id=101),记录成功率和延迟,分析乐观锁性能瓶颈(如重试次数增加导致延迟上升),并考虑用悲观锁(如SELECT FOR UPDATE)处理核心冲突点。def select_course(user_id, course_id):
with db.transaction(): # 开启REPEATABLE READ隔离级别事务
# 检查用户选课数量限制
user_courses = db.query("SELECT COUNT(*) FROM enrollment WHERE user_id = ?", user_id)
if user_courses[0]['count'] >= 3: # 假设最多选3门
raise Exception("用户已选满课程")
# 检查课程剩余名额
course = db.query("SELECT remain_count, version FROM course WHERE course_id = ?", course_id)
if not course or course[0]['remain_count'] <= 0:
raise Exception("课程已满")
# 插入选课记录
db.execute("INSERT INTO enrollment (user_id, course_id, enroll_time) VALUES (?, ?, NOW())", user_id, course_id)
# 更新课程表剩余名额和版本(乐观锁更新)
db.execute("UPDATE course SET remain_count = remain_count - 1, version = version + 1 WHERE course_id = ? AND version = ?", course_id, course[0]['version'])
db.commit()
5) 【面试口播版答案】
好的,面试官。针对好未来在线课程系统的选课操作,我设计的测试用例核心是通过REPEATABLE READ隔离级别的事务保证数据一致性,并使用乐观锁(版本号机制+重试3次+1-3秒延迟)处理并发冲突,同时验证用户选课数量限制和主键约束。首先,选课涉及用户表(user_id)、课程表(course_id、剩余名额remain_count)、选课记录表(关联user_id和course_id)。我会用事务包裹整个流程,确保“检查用户选课数量→检查课程剩余名额→插入选课记录→更新课程表”这四个步骤要么全成功要么全失败(原子性),保证数据一致性。然后,处理并发时采用乐观锁:选课前读取课程表的version,插入记录后更新version,若版本不一致则重试(最多3次,每次延迟1-3秒),避免死锁。具体测试会模拟单用户选课成功(验证数据一致),以及多线程同时选同一门课的场景(验证并发下数据正确,用户未超限),还有极端高并发(1000线程)测试,记录成功率和延迟,分析乐观锁性能瓶颈,并考虑用悲观锁处理核心冲突点。这样既能保证选课后各表数据满足业务规则,又能处理并发冲突。
6) 【追问清单】
SELECT FOR UPDATE)处理核心冲突点,或优化乐观锁参数(如增加重试次数、调整延迟策略),或引入分布式锁(如Redis)。7) 【常见坑/雷区】