Node.js如何实现先删除S3文件再执行MySQL删除操作
问题现象
开发需同时删除S3存储桶图片、对应MySQL数据库记录的API接口,出现执行顺序异常:数据库删除操作先于S3删除执行,S3删除逻辑查询媒体记录时返回null,无法定位待删除的S3文件。
预期执行顺序:删除S3文件 → 删除数据库记录
相关代码
路由层代码
// Router code: //req.body为ID数组,示例值:[ 213, 214] //S3删除逻辑 req.body.forEach((mediaId) => { mediaService.removeMediaItem(mediaId); }); //数据库删除逻辑 await recycleBinService.deleteRecycledMedia(req.body);
S3删除业务方法
removeMediaItem逻辑为:根据传入的mediaId查询media表获取文件名,再调用s3Connection.deleteFile删除S3对应文件
const removeMediaItem = async (mediaId) => { const image = await _db.findOne("media", { id: mediaId }); console.log("image: ", image); await s3Connection.deleteFile(image.file_name); };
数据库删除业务方法
deleteRecycledMedia逻辑为:依次执行两条原生SQL,分别删除media表、recycle_bin表中匹配ID的记录
const wheresMedia = _apiDb.orWhere("id", mediaIds); const wheresRecycle = _apiDb.orWhere("media", mediaIds); // 按传入顺序执行两条SQL await _apiDb.doubleRawSql( `DELETE from media ${wheresMedia}`, `DELETE from recycle_bin ${wheresRecycle}` );
问题根因
removeMediaItem是async声明的异步函数,在forEach循环中调用时没有添加await等待执行完成,forEach本身也不支持等待内部异步任务,循环会快速发起所有S3删除的异步调用后,直接进入后续的数据库删除逻辑。- 数据库删除操作无需等待S3删除任务全部完成,会提前删除media表中的对应记录,此时尚未执行完的S3删除逻辑再查询media表,就会获取到
null结果。
修复方案
- 替换原有
forEach无等待调用的写法,使用Promise.all等待所有S3删除任务全部执行完成后,再执行数据库删除操作,保证执行顺序符合预期。
修复后的路由代码:
// 等待所有S3文件删除任务全部完成 await Promise.all(req.body.map((mediaId) => mediaService.removeMediaItem(mediaId))); // S3操作全部执行完毕后,再执行数据库删除 await recycleBinService.deleteRecycledMedia(req.body);
- 增加空值容错:在
removeMediaItem方法中增加查询结果判空逻辑,避免记录不存在时触发空指针报错,同时打印异常日志方便排查。
const removeMediaItem = async (mediaId) => { const image = await _db.findOne("media", { id: mediaId }); console.log("image: ", image); if (!image) { console.error(`对应媒体记录不存在,mediaId:${mediaId}`); return; } await s3Connection.deleteFile(image.file_name); };
内容的提问来源于stack exchange,提问作者jimbus
相关产品推荐
相关产品推荐

