У меня есть файлы, хранящиеся в базе данных MySQL как longblob. Он работает для загрузки файлов определенного размера, но когда файлы становятся больше, они не загружаются в базу данных, и сервер зависает. Я понимаю, что это проблема с памятью, и я знаю, что вы можете увеличить размер max_allowed_packet, чтобы решить эту проблему. Однако у меня нет доступа или разрешений на изменение этой переменной в mysql, поэтому мне нужно исправить это другим способом, если это возможно? Я использую nodeJS + express с multer для загрузки файлов в базу данных.
Я думал каким-то образом использовать потоки или буфер, но я не уверен, как это сделать.
Конечная точка загрузки файлов сейчас выглядит так:
router.post(
"/uploadFiles",
(req, res, next) => {
console.info(req.body);
next();
},
upload.array("file"),
async (req, res) => {
try {
if (req.body.filesToUpload) {
let uploadedFiles = JSON.parse(req.body.filesToUpload);
if (uploadedFiles.length > 0) {
uploadedFiles.map(async (file, index) => {
uploadedFiles.map(async (file, index) => {
values = {
ClientID: req.body.ClientID,
FileName: file.FileName,
FileType: req.files[index].mimetype,
FileSize: req.files[index].size,
Content: req.files[index].buffer,
Date: file.Date,
Comment: file.Comment,
};
await addFileToDb(values);
});
}
}
return res.send();
} catch (error) {
next(new ErrorHandler(401, req.url, error));
}
}
);
let addFileToDb = async (values) => {
return new Promise(async (resolve, reject) => {
try {
await connection.query(
"INSERT INTO FileUpload SET ?",
values,
(err, result, fields) => {
if (err) return reject(err);
return resolve(result);
}
);
} catch (error) {
return reject(error);
}
});
};
Как я могу изменить способ загрузки файлов, чтобы он работал для загрузки файлов большего размера?
Любая помощь приветствуется.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Предполагая, что req.files[index].buffer - это уже весь файл, вы можете сделать следующее:
status='pending')status='done').(В более ранней версии этого ответа я опубликовал пример, в котором использовался UPDATE table SET Content = CONCAT(Content, ?), но, по-видимому, это не работает; результат CONCAT не может быть больше, чем размер пакета.)
Создайте отдельные строки в таблице и выберите все строки в этой таблице, если вы хотите вывести файл. Таблица будет выглядеть примерно так:
id | FileId | Content
---+--------+---------
1 | 1 | aabbccdd
2 | 1 | eeff1122
3 | 1 | 33
4 | 2 | 44556677
5 | 2 | 889900
Это похоже на систему хранения MongoDB GridFS.
// After your "await addFileToDb(values);", flag the file as "pending" and:
let offset = 0;
const maxSize = 1024 * 1024; // 1mb
const b = req.files[index].buffer;
while (offest + maxSize <= b.length) {
// Slice off a chunk of the entire file.
const chunk = b.slice(offset, offset + maxSize);
offset += maxSize;
// INSERT INTO FileChunks (FileId, Content) VALUES (?, ?)
}
// Flag the row as "finished uploading"
(Обязательно тщательно протестируйте и добавьте обработку ошибок)
При загрузке файла выполните:
SELECT Content
FROM FileChunks
WHERE FileChunks.FileId = ?
ORDER BY id ASC
# const fileContent = Buffer.concat( rows.map(row => row.Content) );
Обязательно выполняйте запросы INSERTпоследовательно с await в цикле while(), а не в параллели с Promise.all.
В качестве отступления: не спамите async везде. Правило: функция, которая не использует await в своем теле (! - вложенные функции не учитываются), не должна быть async.
Я соответствующим образом переписал вашу текущую настройку. Обратите внимание, что на самом деле только одна функция является async:
const addFileToDb = (values) =>
new Promise((resolve, reject) =>
connection.query("INSERT INTO FileUpload SET ?", values, (err, result, fields) =>
err ? reject(err) : resolve(result)
)
);
router.post("/uploadFiles",
upload.array("file"),
async (req, res) => {
try {
if (!req.body.filesToUpload) return res.status(400).send('nothing uploaded');
const uploadedFiles = JSON.parse(req.body.filesToUpload);
if (!uploadedFiles.length) return res.status(400).send('nothing uploaded');
const uploadPromises = uploadedFiles.map((file, index) =>
addFileToDb({
ClientID: req.body.ClientID,
FileName: file.FileName,
FileType: req.files[index].mimetype,
FileSize: req.files[index].size,
Content: req.files[index].buffer,
Date: file.Date,
Comment: file.Comment,
})
);
await Promise.all(uploadPromises);
res.send();
} catch (error) {
res.status(500).send('oops');
}
}
);
Кроме того, это загружает все параллельно, а не в цепочку.