Я получал вышеупомянутую ошибку «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") - та же ошибка.

Что я действительно обнаружил, так это то, что если я запускаю только одну из функций инициализации за раз, я не получаю ошибку, но если я соединяю функции инициализации, запуская их одну за другой, я получаю ошибку.

Любые идеи/предложения приветствуются!

РЕДАКЦИИ: Мелкие исправления опечаток

0
HiDefLoLife 26 Фев 2015 в 22:37
Я не знаю NodeJS. Но ваша функция выполняет db.run("BEGIN") при каждом вызове. Поместите db.run("BEGIN") в качестве запуска только один раз. Также db.run("COMMIT") в конце цикла.
 – 
itzMEonTV
26 Фев 2015 в 22:52
Попробуйте также db.run("BEGIN TRANSACTION").
 – 
itzMEonTV
26 Фев 2015 в 22:56
Спасибо, но я уже пробовал db.run("НАЧАТЬ ТРАНЗАКЦИЮ"). Кроме того, каждая функция вызывается только один раз "BEGIN" и "COMMIT" - они заканчиваются. Но, возможно, из-за асинхронной природы Node/JS они могут пересекаться. Позвольте мне взглянуть на это.
 – 
HiDefLoLife
26 Фев 2015 в 23:17

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. /Контроль-поток.

4
Gigo 26 Авг 2015 в 03:03

Хорошо, внес небольшие изменения в код, и теперь он работает!

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");
  }
});
...
}

Надеюсь, что это поможет любому с подобными проблемами.

0
HiDefLoLife 27 Фев 2015 в 00:21