我在数据库初始化过程中遇到了上述"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");
}
});
...
}
希望这能帮助任何有类似问题的人。