欢迎光临
我们一直在努力

基于 MongoDB 的视频播放进度(断点续播)实现方案

文章目录

  • 一、业务场景说明
  • 二、为什么选择 MongoDB 存储播放进度
  • 三、MongoDB 数据模型设计
  • 四、获取视频播放进度(断点续播)
  • 五、更新视频播放进度
  • 六、前端播放流程说明(配合后端)
  • 七、常见问题与优化点
  • 八、方案总结

在视频类业务中,断点续播 是最基础、也是最核心的能力之一。 本文将介绍如何 仅使用 MongoDB 实现视频播放进度的保存与恢复, 适用于在线视频、课程学习、长视频播放等场景。


一、业务场景说明

视频播放过程中通常存在以下需求:

  • 用户播放视频过程中可能随时退出页面
  • 再次进入视频页面时,需要从上次播放位置继续播放
  • 播放器会 每隔一段时间(如 10 秒)自动保存播放进度
  • 后端需要支持 高频写入 + 快速查询 在这里插入图片描述

二、为什么选择 MongoDB 存储播放进度

原因说明
写入频繁 每 5~10 秒保存一次进度
数据结构简单 用户 + 视频 + 秒数
不需要事务 单条数据即可
扩展性好 适合大用户量

👉 MongoDB 的 文档模型 + 高并发写入能力,非常适合播放进度这类数据。


三、MongoDB 数据模型设计

1、播放进度实体类

@Data
@Document(collection = "user_video_play_process")
public class UserVideoPlayProcess {

@Id
private String id;

/** 用户ID */
private Long userId;

/** 视频ID */
private Long videoId;

/** 当前播放到的秒数 */
private BigDecimal playSecond;

/** 视频总时长(秒) */
private BigDecimal duration;

/** 是否播放完成:0-未完成,1-已完成 */
private Integer isFinished;

/** 创建时间 */
private Date createTime;

/** 更新时间 */
private Date updateTime;
}

2、索引设计

db.user_video_play_process.createIndex(
{ userId: 1, videoId: 1 },
{ unique: true }
)

👉 保证:

  • 一个用户 + 一个视频 只有一条播放进度
  • 查询和更新都非常快

四、获取视频播放进度(断点续播)

接口说明

  • 用途:进入视频页面时,获取上次播放位置
  • 返回值:秒数(用于前端 seek)

Controller

@GetMapping("/getPlaySecond/{videoId}")
public Result<BigDecimal> getPlaySecond(@PathVariable Long videoId) {
Long userId = AuthContextHolder.getUserId();
return Result.ok(
videoPlayProcessService.getPlaySecond(userId, videoId)
);
}

Service 实现

@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();
}


五、更新视频播放进度

前端上报规则

  • 播放过程中每 10 秒 上报一次
  • 视频暂停 / 页面关闭 / 切换视频时强制上报
  • 拖动进度条结束后上报

接收参数 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 核心实现(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

  • 存在即更新
  • 不存在即插入
  • 一条语句完成,避免并发问题
  • 性能优于 find + save

六、前端播放流程说明(配合后端)

1. 进入视频页面
2. 调用 getPlaySecond(videoId)
3. 播放器 seek 到返回的秒数
4. 播放过程中每 10 秒调用 updatePlayProcess
5. 页面关闭 / 切视频时最后一次保存


七、常见问题与优化点

是否需要保存毫秒级?

❌ 不需要 ✔ 秒级即可,节省存储 & 减少写入


如何降低 MongoDB 写压力?

  • 秒数变化 < 3 秒不更新
  • 播放暂停时不上报
  • 拖动结束才上报

是否需要按用户分集合?

❌ 不推荐 ✔ 单集合 + 复合索引更稳妥


八、方案总结

使用 MongoDB 存储视频播放进度, 通过 userId + videoId 唯一索引保证幂等, 利用 upsert 实现高效的断点续播功能。

该方案:

  • 实现简单
  • 性能稳定
  • 易于扩展(学习进度、是否看完)

视频播放进度使用 MongoDB 存储, 通过 upsert 保证高并发下的数据一致性, 实现视频的断点续播功能。

赞(0)
未经允许不得转载:171主机测评 » 基于 MongoDB 的视频播放进度(断点续播)实现方案
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址