简体   繁体   中英

“SQLITE_ERROR: cannot start a transaction within a transaction” with BEGIN … COMMIT transaction control

I had been getting the above-mentioned "SQLITE_ERROR: cannot start a transaction within a transaction" error during my database initialization process, but did find that there were some suggestions for best practises: here and here .

So, I adjusted my code to add the db.run("BEGIN") and db.run("COMMIT") bookends to hopefully fix the issue, but the error still persists.

Here is what my code looks like:

I call the various initialization functions:

intializeMyTable1(...);
intializeMyTable2(...);
...
intializeMyTableN(...);

Each intialize function is roughly the same:

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

I've tried db.run("END") instead of db.run("COMMIT") - same error.

What I did find is that if I run only one of the initialization functions at a time, I don't get the error, but if I chain the initialization functions, running them one after the other, I get the error.

Any ideas/suggestions are appreciated!

EDITS: Minor typo fixes

Unless you omitted a call to db.serialize() in your posts you did not actually fix your error.

All the statements are executed asynchronously, which means that db.run does not actually run the statement but rather enqueues it. Enqueued statements are executed in parallel if not explicitly wrapped in db.serialize() .

Thus, the following is not expected to be executed in the given order, one after the other:

db.run("BEGIN");
db.run("*do sql stuff*");
db.run("COMMIT");
db.run("BEGIN");
db.run("*do sql stuff*");
db.run("COMMIT");

It might be executed as

db.run("BEGIN");
db.run("BEGIN");
db.run("COMMIT");
db.run("COMMIT");
db.run("*do sql stuff*");
db.run("*do sql stuff*");

or any other random order. That explains your error message "cannot start a transaction within a transaction".

Have a look at https://github.com/mapbox/node-sqlite3/wiki/Control-Flow .

OK, made some minor changes to the code and it works now!

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

Hope that helps anyone with similar problems.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM