node.js - 将文件 API 与用于文件保存或删除的事务相结合
问题描述
我正在使用节点 8.11.1 和pg-promise 8.4.4来处理 PostgreSQL 中的查询和事务。这是关于节点的,但我想在其他服务器/工具中也是相同的逻辑。
场景很常见。我想将图像文件保存在文件夹中,然后如果成功,则将其详细信息插入数据库中,获取返回的 id,然后在辅助的多对多表中进行另一次插入。
显然,我需要一个用于插入查询的事务。但是实际的文件保存呢?我的方法是
fs.rename(oldpath, newpath, (err) => {
if (err){throw new Error ;}
db.tx('my-transaction', t => {
return t.one('INSERT INTO images(whatever) VALUES($1) RETURNING id', ['whatever'])
.then(user => {
return t.batch([
t.none('INSERT INTO mtm(userId, name) VALUES($1, $2)', [user.id, 'created'])
]);
});
})
.then(data => {
// success
})
.catch(error => {
// error
});
}); //fs rename
好的,如果用 保存图像文件时没有错误fs.rename
,则继续事务。
如果保存图像时出现错误,则不会执行任何操作,一切都很好。
但是问题来了,如果图片保存了,交易出错了怎么办?我最终会保存一张图像,而数据库中没有任何内容。当然,用户会收到一个错误并且必须重新上传,但我的服务器中仍然有与任何内容无关的图像。我想避免这种情况。
解决方案是将图像保存合并到事务中,因此如果出现任何故障,则什么都不会完成。我怎样才能做到这一点?我不知道文件 API 是否可以在与查询相关的事务中。我什至不知道我在这里的心态是否正确。
请建议或帮助我编写代码。
谢谢
解决方案
如果事务失败,只需删除文件(或者您可以将其重命名,如果您愿意):
const fs = require('fs-extra');
async function saveAll(oldpath, newpath) {
await fs.rename(oldpath, newpath);
try {
return await db.tx('my-transaction', async t => {
const imageId = await t.one('INSERT INTO images(whatever) VALUES($1) RETURNING id', ['whatever'], a => a.id);
await t.none('INSERT INTO mtm(userId, name) VALUES($1, $2)', [imageId, 'created']);
return imageId;
});
} catch (e) {
await fs.unlink(newpath); // deleting the file
throw e;
}
}
如果成功,函数saveAll
将返回 new imageId
,如果失败则抛出错误:
async test() {
try {
const imageId = await saveAll('old-path', 'new-path');
// we are all good
} catch(e) {
// something failed, as per the error details
}
}
推荐阅读
- python - py2neo:无法创建图形
- android - 在 Android Studio 上实现 firebase 的错误消息
- android - 如何加入 ObjectBox
- python-3.x - “charmap”编解码器无法编码位置 XX 中的字符
- php - 如果在php中的下划线之前找到一系列数字,如何取出
- java - Spring Boot:应用程序显示 404 错误
- android - Android - com.android.support:appcompat-v7:22.2.1 中的数字 22 是什么?
- android - 我正在使用 Android Studio 3.1.3,但出现了一些错误
- python - 将 .log 文件导入 Jupyter 笔记本
- git - React 原生节点模块:如何在 git 中保持 Android 模块的变化?