使用MongoDB實現(xiàn)視頻播放進度的保存與恢復(fù)(斷點續(xù)播)
一、業(yè)務(wù)場景說明
視頻播放過程中通常存在以下需求:
- 用戶播放視頻過程中可能隨時退出頁面
- 再次進入視頻頁面時,需要從上次播放位置繼續(xù)播放
- 播放器會 每隔一段時間(如 10 秒)自動保存播放進度
- 后端需要支持 高頻寫入 + 快速查詢

二、為什么選擇 MongoDB 存儲播放進度
| 原因 | 說明 |
|---|---|
| 寫入頻繁 | 每 5~10 秒保存一次進度 |
| 數(shù)據(jù)結(jié)構(gòu)簡單 | 用戶 + 視頻 + 秒數(shù) |
| 不需要事務(wù) | 單條數(shù)據(jù)即可 |
| 擴展性好 | 適合大用戶量 |
MongoDB 的 文檔模型 + 高并發(fā)寫入能力,非常適合播放進度這類數(shù)據(jù)。
三、MongoDB 數(shù)據(jù)模型設(shè)計
1、播放進度實體類
@Data
@Document(collection = "user_video_play_process")
public class UserVideoPlayProcess {
@Id
private String id;
/** 用戶ID */
private Long userId;
/** 視頻ID */
private Long videoId;
/** 當前播放到的秒數(shù) */
private BigDecimal playSecond;
/** 視頻總時長(秒) */
private BigDecimal duration;
/** 是否播放完成:0-未完成,1-已完成 */
private Integer isFinished;
/** 創(chuàng)建時間 */
private Date createTime;
/** 更新時間 */
private Date updateTime;
}
2、索引設(shè)計
db.user_video_play_process.createIndex(
{ userId: 1, videoId: 1 },
{ unique: true }
)
保證:
- 一個用戶 + 一個視頻 只有一條播放進度
- 查詢和更新都非???/li>
四、獲取視頻播放進度(斷點續(xù)播)
接口說明
- 用途:進入視頻頁面時,獲取上次播放位置
- 返回值:秒數(shù)(用于前端 seek)
Controller
@GetMapping("/getPlaySecond/{videoId}")
public Result<BigDecimal> getPlaySecond(@PathVariable Long videoId) {
Long userId = AuthContextHolder.getUserId();
return Result.ok(
videoPlayProcessService.getPlaySecond(userId, videoId)
);
}
Service 實現(xiàn)
@Override
public BigDecimal getPlaySecond(Long userId, Long videoId) {
Query query = Query.query(
Criteria.where("userId").is(userId)
.and("videoId").is(videoId)
);
UserVideoPlayProcess process =
mongoTemplate.findOne(query, UserVideoPlayProcess.class);
return process == null ? BigDecimal.ZERO : process.getPlaySecond();
}
五、更新視頻播放進度
前端上報規(guī)則
- 播放過程中每 10 秒 上報一次
- 視頻暫停 / 頁面關(guān)閉 / 切換視頻時強制上報
- 拖動進度條結(jié)束后上報
接收參數(shù) VO
@Data
public class VideoPlayProcessVo {
private Long videoId;
private BigDecimal playSecond;
private BigDecimal duration;
}
Controller
@PostMapping("/updatePlayProcess")
public Result updatePlayProcess(
@RequestBody VideoPlayProcessVo vo) {
Long userId = AuthContextHolder.getUserId();
videoPlayProcessService.updatePlayProcess(userId, vo);
return Result.ok();
}
Service 核心實現(xiàn)(Upsert 思想)
@Override
public void updatePlayProcess(Long userId, VideoPlayProcessVo vo) {
Query query = Query.query(
Criteria.where("userId").is(userId)
.and("videoId").is(vo.getVideoId())
);
boolean finished = vo.getPlaySecond().compareTo(
vo.getDuration().multiply(new BigDecimal("0.95"))
) >= 0;
Update update = new Update()
.set("playSecond", vo.getPlaySecond())
.set("duration", vo.getDuration())
.set("isFinished", finished ? 1 : 0)
.set("updateTime", new Date())
.setOnInsert("userId", userId)
.setOnInsert("videoId", vo.getVideoId())
.setOnInsert("createTime", new Date());
mongoTemplate.upsert(
query,
update,
UserVideoPlayProcess.class
);
}
為什么用 upsert
- 存在即更新
- 不存在即插入
- 一條語句完成,避免并發(fā)問題
- 性能優(yōu)于
find + save
六、前端播放流程說明(配合后端)
1. 進入視頻頁面 2. 調(diào)用 getPlaySecond(videoId) 3. 播放器 seek 到返回的秒數(shù) 4. 播放過程中每 10 秒調(diào)用 updatePlayProcess 5. 頁面關(guān)閉 / 切視頻時最后一次保存
七、常見問題與優(yōu)化點
是否需要保存毫秒級?
? 不需要
? 秒級即可,節(jié)省存儲 & 減少寫入
如何降低 MongoDB 寫壓力?
- 秒數(shù)變化 < 3 秒不更新
- 播放暫停時不上報
- 拖動結(jié)束才上報
是否需要按用戶分集合?
? 不推薦
? 單集合 + 復(fù)合索引更穩(wěn)妥
八、方案總結(jié)
使用 MongoDB 存儲視頻播放進度,
通過 userId + videoId 唯一索引保證冪等,
利用 upsert 實現(xiàn)高效的斷點續(xù)播功能。
該方案:
- 實現(xiàn)簡單
- 性能穩(wěn)定
- 易于擴展(學(xué)習(xí)進度、是否看完)
視頻播放進度使用 MongoDB 存儲,
通過 upsert 保證高并發(fā)下的數(shù)據(jù)一致性,
實現(xiàn)視頻的斷點續(xù)播功能。
以上就是使用MongoDB實現(xiàn)視頻播放進度的保存與恢復(fù)(斷點續(xù)播)的詳細內(nèi)容,更多關(guān)于MongoDB視頻播放進度保存與恢復(fù)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
MongoDB中數(shù)據(jù)的替換方法實現(xiàn)類Replace()函數(shù)功能詳解
這篇文章主要介紹了MongoDB中數(shù)據(jù)的替換方法實現(xiàn)類Replace()函數(shù)功能詳解,需要的朋友可以參考下2020-02-02

