Node.jsでsqlite3のserializeを使うときの注意点


sqlite3のserialize

sqlite3の処理は通常callbackを使って完了したことを待つことができます。

db.run("INSERT INTO foo ...", (err) => {
  // 完了!
});

async/awaitを使っていい感じに書くと、こうでしょう。

async function run(sql) {
  return new Promise((resolve, reject) => {
    db.run(sql, (err) => {
      if (err) reject();
      else resolve();
    });
  });
}

await run("INSERT INTO foo ...");

しかし、serializeを使うと、何も考えずに同期的に書ける方法があります。便利!

db.serialize(() => {
  db.run("...");
  db.run("...");
  db.run("...");
});

注意点

残念ながら、同期的に書くことができるのはserialize内のコードだけで、それ以外は非同期で実行されてしまいます。
つまり、以下のようなコードは、非同期で同時に実行される可能性があります。
おそらく、いっこめのINSERTが終わったあたりでSELECT文が実行されてしまうでしょう。

db.serialize(() => {
  db.run("INSERT INTO FOO ...");
  db.run("INSERT INTO FOO ...");
  db.run("INSERT INTO FOO ...");
});
db.all("SELECT * FROM foo");

対策

serializeをいい感じにasync/awaitでラップしましょう。
最後の処理で、resolveしてあげます。

async function serialize() {
  new Promise(resolve => {
    db.serialize(() => {
      db.run("INSERT INTO FOO...");
      db.run("INSERT INTO FOO...");
      db.run("INSERT INTO FOO...");
      db.run("INSERT INTO FOO...", () => resolve());
    });
  });
}

以上です。よろしくお願いいたします。