Я получал вышеупомянутую ошибку «SQLITE_ERROR: невозможно начать транзакцию внутри транзакции» во время процесса инициализации моей базы данных, но обнаружил, что есть несколько рекомендаций по передовым методам: здесь и здесь.
Итак, я изменил свой код, чтобы добавить форзацы db.run("BEGIN") и db.run("COMMIT"), чтобы, надеюсь, решить проблему, но ошибка все еще сохраняется.
Вот как выглядит мой код:
Я вызываю различные функции инициализации:
intializeMyTable1(...);
intializeMyTable2(...);
...
intializeMyTableN(...);
Каждая функция инициализации примерно одинакова:
initializeMyTable1: function(...){
...
db.run("BEGIN")
db.run("CREATE TABLE if not exists MyTable1 (...)", function (err) {
if (err !== null) {
logger.error("Database Error:" + err);
}
else {
for (var i = 0; i < SomeNumber; i++) {
db.run("INSERT INTO MyTable1 (...) VALUES (...)", function (err) {
if (err !== null) {
...
}
});
}
}
});
db.run("COMMIT");
...
}
Я пробовал db.run("END") вместо db.run("COMMIT") - та же ошибка.
Что я действительно обнаружил, так это то, что если я запускаю только одну из функций инициализации за раз, я не получаю ошибку, но если я соединяю функции инициализации, запуская их одну за другой, я получаю ошибку.
Любые идеи/предложения приветствуются!
РЕДАКЦИИ: Мелкие исправления опечаток
2 ответа
Если вы не пропустили вызов db.serialize()
в своих сообщениях, вы на самом деле не исправили свою ошибку.
Все операторы выполняются асинхронно, что означает, что db.run
на самом деле не запускает оператор, а ставит его в очередь. Поставленные в очередь операторы выполняются параллельно, если они явно не заключены в db.serialize()
.
Таким образом, не ожидается, что следующее будет выполняться в заданном порядке одно за другим:
db.run("BEGIN");
db.run("*do sql stuff*");
db.run("COMMIT");
db.run("BEGIN");
db.run("*do sql stuff*");
db.run("COMMIT");
Это может быть выполнено как
db.run("BEGIN");
db.run("BEGIN");
db.run("COMMIT");
db.run("COMMIT");
db.run("*do sql stuff*");
db.run("*do sql stuff*");
Или любой другой случайный порядок. Это объясняет ваше сообщение об ошибке «невозможно начать транзакцию внутри транзакции».
Взгляните на https://github.com/mapbox/node-sqlite3/wiki. /Контроль-поток.
Хорошо, внес небольшие изменения в код, и теперь он работает!
initializeMyTable1: function(...){
...
// treat the CREATE as independent of my BEGIN ... COMMIT flow
db.exec("CREATE TABLE if not exists MyTable1 (...)", function (err) {
if (err !== null) {
logger.error("Database Error:" + err);
}
else {
// BEGIN ... COMMIT bookends only relate to INSERTs
db.run("BEGIN");
for (var i = 0; i < SomeNumber; i++) {
db.run("INSERT INTO MyTable1 (...) VALUES (...)", function (err) {
if (err !== null) {
...
}
});
}
db.run("COMMIT");
}
});
...
}
Надеюсь, что это поможет любому с подобными проблемами.
Похожие вопросы
Связанные вопросы
Новые вопросы
node.js
Node.js — это основанная на событиях, неблокирующая, асинхронная среда выполнения ввода-вывода, использующая движок Google V8 JavaScript и библиотеку libuv. Он используется для разработки приложений, которые интенсивно используют возможность запуска JavaScript как на стороне клиента, так и на стороне сервера и, следовательно, выигрывают от возможности повторного использования кода и отсутствия переключения контекста.
db.run("BEGIN")
при каждом вызове. Поместитеdb.run("BEGIN")
в качестве запуска только один раз. Такжеdb.run("COMMIT")
в конце цикла.db.run("BEGIN TRANSACTION")
.