最近、nodeと node-sqlite を使用してsqlite3を操作することを学んでいます。これがサンプルです。
var sqlite3 = require('sqlite3');
var db = new sqlite3.Database(':memory:');
db.serialize(function() {
db.run("CREATE TABLE test(info TEXT)");
db.run("INSERT INTO test (info) VALUES ('info1')");
})
db.close();
ドキュメントでは、db.serialized
を使用してSQL行が順番に実行されるようになっていると述べましたが、db.serialize
なしで順番に実行されないので、イベントから引き出されて混乱しましたキューに入れて順番に実行しますか?ここでどのように機能しますか?
実行するsqlが1つしかない場合、次のようにdb.serialize
なしで実行しても安全ですか?
var sqlite3 = require('sqlite3');
var db = new sqlite3.Database(':memory:');
db.run("CREATE TABLE test(info TEXT)");
db.close();
serialize()
関数内の各コマンドは、次のコマンドが開始する前にfinishで実行されることが保証されています。
あなたの例では、INSERT
が実行される前に_CREATE TABLE
_が終了します。 serialize()
を使用しなかった場合、_CREATE TABLE
_およびINSERT
ステートメントが並行して実行されます。これらは次から次へと急速に開始するため、テーブルが作成される前にINSERT
が実際に終了し、存在しないテーブルにデータを挿入しようとするとエラーが発生します。
これは、競合条件と呼ばれます。プログラムを実行するたびに異なる勝者が得られる可能性があるためです。 _CREATE TABLE
_がレースに勝った場合、プログラムは正常に動作します。しかし、INSERT
がレースに勝った場合、プログラムはエラーで中断します。誰がレースに勝つかを制御できないので、serialize()
は_CREATE TABLE
_が最後に達するまでINSERT
が開始するのを止め、毎回同じ結果を得るようにします。
ステートメントが1つだけの2番目の例では、serialize()
が引き続き必要です。これは、run()
がSQLクエリを開始しますが、すぐに戻るであり、クエリをバックグラウンドで実行するためです。次のコマンドはデータベースに対するclose()
であるため、クエリの実行中にそれを切断します。
serialize()
は内部クエリの最後が完了するまで返されないため、これを使用すると、クエリが完了するまでclose()
が保留されます。
別の種類のクエリを使用している場合(たとえば、ユーザーがWebページのボタンをクリックしたときに、呼び出し間でデータベースが開いたままになっている場合)、おそらくserialize()
は必要ありません。各クエリに続くコードが、クエリが完了する前にクエリを完了する必要があるかどうかによって異なります。
serialize()
を使用するかどうかを決定するとき、非シリアル化されたクエリをコメントアウトされているように考え、コードが引き続き機能するかどうかを確認すると役立ちます。上記の最初の例では、_CREATE TABLE
_コマンドを削除すると、次のINSERT
ステートメントが壊れます(挿入するテーブルがないため)。したがって、これらをシリアル化する必要があります。ただし、2つの_CREATE TABLE
_コマンドがある場合、一方を削除しても他方には影響しないため、これらの2つのコマンドをシリアル化する必要はありません。
(このヒントはclose()
には適用されません-ただし、すべての実行が終了したらclose()
を呼び出すだけです。)
これは SQLiteドキュメント で見つけました。
database#closeメソッドは常に排他モードで実行されます。つまり、すべての以前のクエリが完了するまで待機し、クローズが保留されている間、node-sqlite3は他のクエリを実行しません。
最終的な質問に対する答えはyesのようです。実行するクエリが1つしかない場合、serialize関数は必要ありません。クエリが終了する前にデータベースが閉じられることを心配する必要はありません。SQLiteはそれをしないほど賢いからです! :)