
1) 【一句话结论】
采用“主表(带乐观锁+操作类型)+设备同步表+离线缓存(带30分钟有效期)”的三层架构,通过乐观锁解决并发冲突,结合实时WebSocket推送与离线缓存批量同步,实现多设备最终一致性,并明确离线数据有效期与设备同步策略(手机端5分钟,PC端实时)。
2) 【原理/概念讲解】
老师讲解:用户学习进度表需支持多设备同步与实时更新,核心设计分三部分:
user_learning_progress):存储核心进度数据,字段包括用户ID(user_id)、课程ID(course_id)、章节ID(chapter_id)、当前进度点(current_progress_point)、最后更新时间(last_update_time)、版本号(version,乐观锁)、操作类型(operation_type,如“学习”“删除”)。device_sync):记录设备ID(device_id)、用户ID(user_id)、最后同步时间(last_sync_time)、设备类型(PC/手机/平板)。offline_cache):存储设备离线时的本地进度(用户ID、课程ID、章节ID、进度点、离线时间戳、有效期)。user_id + course_id + chapter_id建复合索引,加速查询与更新;device_id + user_id建索引,支持设备状态查询;user_id + course_id + chapter_id建索引,支持离线数据批量同步。is_valid=0),并推送通知其他设备,避免重复记录。3) 【对比与适用场景】
| 设计方案 | 定义 | 特性 | 使用场景 | 注意点 |
|---|---|---|---|---|
| 单表结构 | 所有进度数据存于一张表 | 简单,但并发冲突严重 | 小规模系统,设备少 | 并发高时性能差,冲突处理复杂 |
| 主表+设备表 | 主表存储核心进度,设备表记录设备状态 | 分离数据,减少主表压力 | 大规模系统,多设备同步 | 需额外同步设备表,逻辑复杂 |
| 乐观锁+操作类型 | 主表加版本号+操作类型 | 通过冲突检测+业务逻辑解决冲突 | 对实时性要求高的场景 | 需回滚/合并,极端场景(如删除)需标记无效 |
| 离线缓存+有效期 | 主表+离线缓存(带有效期) | 处理离线同步,避免数据不一致 | 移动端多场景(如网络波动) | 有效期控制,避免过期数据同步 |
| 分布式事务 | 统一控制多设备更新 | 强一致性 | 极高实时性要求 | 事务开销大,可能阻塞 |
4) 【示例】
(C++伪代码,展示离线缓存有效期与设备同步策略)
// 更新学习进度(含离线处理与重试)
void updateProgress(int userId, int courseId, int chapterId, int progressPoint, DeviceType deviceType, OperationType opType) {
if (isOffline(deviceType)) {
// 离线缓存,检查有效期(30分钟内)
if (isCacheValid(userId, courseId, chapterId)) {
updateLocalCache(userId, courseId, chapterId, progressPoint);
} else {
return; // 过期,丢弃
}
} else {
// 在线更新
int currentVersion = getProgressVersion(userId, courseId, chapterId);
int affected = updateProgressWithVersion(
userId, courseId, chapterId, progressPoint, currentVersion + 1, opType
);
if (affected == 0) {
// 版本冲突,回滚并重试(最多3次)
handleConflict(userId, courseId, chapterId, currentVersion, opType);
retryUpdate(progressPoint, deviceType, opType, 3);
} else {
// 更新成功,同步其他设备
syncToOtherDevices(userId, courseId, chapterId, progressPoint, opType);
}
}
}
// 离线缓存更新(有效期30分钟)
void updateLocalCache(int userId, int courseId, int chapterId, int progressPoint) {
localCache[userId][courseId][chapterId] = {progressPoint, time(nullptr) + 30*60};
}
// 上线后同步离线数据(按设备类型策略)
void syncOfflineData(int userId, DeviceType deviceType) {
if (deviceType == Mobile) {
// 手机端,5分钟同步一次
if (time(nullptr) - lastSyncTime[userId] < 300) return;
lastSyncTime[userId] = time(nullptr);
} else {
// PC端,实时同步
syncNow(userId);
}
for (auto& entry : localCache[userId]) {
if (checkConflict(entry.first, entry.second, entry.third)) {
mergeConflict(entry.first, entry.second, entry.third);
}
updateDatabase(entry.first, entry.second, entry.third, entry.fourth);
}
clearLocalCache(userId);
}
5) 【面试口播版答案】(约90秒)
“面试官您好,针对用户学习进度表的多设备同步需求,我的设计核心是分层架构结合最终一致性。首先,表结构上,主表存储核心进度(用户ID、课程ID、章节ID、当前进度点、版本号、操作类型),设备同步表记录设备最后同步时间,离线缓存表包含离线时间戳和30分钟有效期。索引方面,主表按用户+课程+章节建复合索引,设备表按设备ID+用户ID索引。冲突解决用乐观锁,操作类型区分(如删除需标记无效并通知其他设备)。同步机制通过WebSocket实时推送,离线时缓存本地(有效期30分钟内),手机端5分钟同步,PC端实时同步。这样既保证多设备最终一致,又处理了离线场景和网络波动。”
6) 【追问清单】
is_valid=0),并推送通知其他设备,检查时跳过无效记录,确保数据一致性。7) 【常见坑/雷区】