"SQLITE_ERROR: cannot start a transaction within a transaction"与开始...提交事务控制



我在数据库初始化过程中遇到了上述"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.rrun("COMMIT")——同样的错误。

我发现,如果我一次只运行一个初始化函数,我不会得到错误,但如果我链接初始化函数,一个接一个地运行它们,我会得到错误。

欢迎提出任何想法/建议!

编辑:轻微的打字错误修复

除非您在帖子中省略了对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/Control-Flow.

好的,对代码做了一些小的更改,现在就可以工作了!

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

希望这能帮助任何有类似问题的人。

相关内容

最新更新