2017-01-31 56 views
7

Ostatnio uczę się używać węzła i node-sqlite3 do manipulowania sqlite3, tutaj jest próbka.Jak działa `db.serialize` w` node-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(); 

Dokumentacja że db.serialized został wykorzystany do zapewnienia linie SQL realizowane były w porządku, ale byłem zdezorientowany, dlaczego nie dostaną wykonywane w kolejności bez db.serialize przecież oni zostać wyciągnięty z kolejki zdarzeń i wykonane w kolejności? Jak to działa tutaj?

A jeśli jest tylko jeden sql do wykonania, czy można bezpiecznie uruchomić go bez db.serialize w następujący sposób?

var sqlite3 = require('sqlite3'); 
var db = new sqlite3.Database(':memory:'); 
db.run("CREATE TABLE test(info TEXT)"); 
db.close(); 
+0

Prawdopodobnie jednym z powodów: http://stackoverflow.com/a/18899872/1936319 – Sizzler

Odpowiedz

8

Każda komenda wewnątrz funkcji serialize() gwarantuje wykończenia wykonywania przed rozpoczęciem następnego jeden.

W twoim przykładzie CREATE TABLE zakończy się przed uruchomieniem INSERT. Jeśli nie używasz serialize(), wówczas instrukcje CREATE TABLE i INSERT będą uruchamiane równolegle. Zaczęliby tak szybko jeden po drugim, że INSERT może faktycznie zakończyć się przed utworzeniem tabeli, dając błąd podczas próby wstawienia danych do tabeli, która nie istnieje.

To się nazywa stan wyścigu, ponieważ za każdym razem, gdy uruchamiasz program, możesz otrzymać innego zwycięzcę. Jeśli wygra wyścig CREATE TABLE, program będzie działał poprawnie. Jeśli jednak wyścig wygra INSERT, program zostanie zerwany z błędem. Ponieważ nie możesz kontrolować, kto wygra wyścig, serialize() zatrzyma INSERT od nawet do momentu, aż CREATE TABLE osiągnie koniec, zapewniając, że za każdym razem uzyskasz taki sam wynik.

W twoim drugim przykładzie z tylko jednym stwierdzeniem wciąż wymagane jest serialize(). Dzieje się tak, ponieważ run() uruchamia zapytanie SQL, ale natychmiast zwraca, pozostawiając zapytanie do uruchomienia w tle. Ponieważ twoja następna komenda to jedna do bazy danych, zostanie ona wyłączona, gdy zapytanie będzie nadal działać.

Ponieważ serialize() nie zwraca, dopóki nie zakończyło się ostatnie z wewnętrznych zapytań, korzystanie z niego zatrzyma się na close(), dopóki zapytanie nie zostanie zakończone.

Jeśli używasz innego typu zapytania (np. W odpowiedzi na kliknięcie przycisku na stronie internetowej, gdzie baza danych pozostaje otwarta między połączeniami), prawdopodobnie nie będziesz potrzebował serialize(). Zależy tylko od tego, czy kod następujący po każdym zapytaniu wymaga, aby kwerendy przed nim zakończyły się, czy też nie.

Przy podejmowaniu decyzji, czy używać serialize(), czy nie, pomocne może być wymyślanie dowolnych zapytań niemumerowanych, tak jakby były one komentowane, a następnie sprawdzanie, czy kod nadal działa. W powyższym pierwszym przykładzie usunięcie polecenia CREATE TABLE spowodowałoby złamanie następującego oświadczenia INSERT (ponieważ wtedy nie byłoby tabeli do wstawienia), dlatego te muszą być serializowane. Ale jeśli masz dwie komendy CREATE TABLE, usunięcie jednego nie wpłynie na inne, więc te dwie komendy nie muszą być serializowane.

(Ta porada nie ma zastosowania do close() jednak - Zasadą jest, aby wywołać tylko close() raz wszystko zakończy uruchomiony.)

+0

Czy jest jakiś sposób zagwarantowania, że ​​wywołanie run() zakończy się przed wywołaniem wywołania zwrotnego? Używam serializacji z punktem zapisu, ale sporadycznie powraca wywołanie zwrotne, ale żadne z moich serializowanych zapytań nie zostało jeszcze uruchomione i widzę, że mój kod wywołuje zamknięcie bazy danych przed ich uruchomieniem. jest to duży problem, ponieważ próbuję użyć danych zwróconych z tych połączeń. – Michael

+0

@ Michael: Nie jestem pewien, co masz na myśli przez 'run()' mającego wywołanie zwrotne, ale wygląda na to, że powinno to być nowe pytanie, a nie komentarz, abyś mógł podać więcej szczegółów. – Malvineous