Récemment, j'apprends à utiliser node et node-sqlite pour manipuler sqlite3, voici un exemple.
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();
La documentation indiquait que db.serialized
a été utilisé pour s'assurer que les lignes SQL ont été exécutées dans l'ordre, mais j'étais confus, pourquoi ne seraient-elles pas exécutées dans l'ordre sans db.serialize
, après tout, ils seraient retirés de la file d'attente des événements et exécutés dans l'ordre? Comment ça marche ici?
Et s'il n'y a qu'un seul SQL à exécuter, est-il sûr de l'exécuter sans db.serialize
comme suit?
var sqlite3 = require('sqlite3');
var db = new sqlite3.Database(':memory:');
db.run("CREATE TABLE test(info TEXT)");
db.close();
Chaque commande à l'intérieur de la fonction serialize()
est garantie de terminer s'exécutant avant le démarrage de la suivante.
Dans votre exemple, CREATE TABLE
Se terminera avant l'exécution de INSERT
. Si vous n'avez pas utilisé serialize()
, les instructions CREATE TABLE
Et INSERT
seront exécutées en parallèle. Ils commenceraient si rapidement l'un après l'autre que le INSERT
pourrait en fait se terminer avant la création de la table, vous donnant une erreur sur la tentative d'insertion de données dans une table qui n'existe pas.
C'est ce qu'on appelle condition de concurrence , car chaque fois que vous exécutez votre programme, vous pouvez obtenir un gagnant différent. Si CREATE TABLE
Remporte la course, le programme fonctionnera bien. Mais si INSERT
gagne la course, le programme s'arrêtera avec une erreur. Comme vous ne pouvez pas contrôler qui remporte la course, serialize()
arrêtera INSERT
de commencer même jusqu'à ce que CREATE TABLE
Atteigne la fin, vous assurant ainsi d'obtenir le même résultat à chaque fois.
Dans votre deuxième exemple avec une seule instruction, serialize()
est toujours requis. En effet, run()
démarre la requête SQL mais retourne immédiatement, laissant la requête s'exécuter en arrière-plan. Puisque votre toute prochaine commande est celle de close()
la base de données, vous la couperez pendant que la requête est toujours en cours d'exécution.
Puisque serialize()
ne revient pas tant que la dernière de ses requêtes internes n'est pas terminée, son utilisation retiendra close()
jusqu'à ce que la requête soit terminée.
Si vous utilisiez un type de requête différent (par exemple en réponse à un utilisateur cliquant sur un bouton sur une page Web, où la base de données est laissée ouverte entre les appels), vous n'auriez probablement pas besoin de serialize()
. Cela dépend simplement si le code qui suit chaque requête nécessite que les requêtes avant qu'elle soit terminée ou non.
Lorsque vous décidez d'utiliser serialize()
ou non, il peut être utile de penser à toutes les requêtes non sérialisées comme si elles étaient commentées, puis de voir si le code fonctionnerait toujours. Dans votre premier exemple ci-dessus, la suppression de la commande CREATE TABLE
Romprait l'instruction INSERT
suivante (car il n'y aurait alors pas de table à insérer), par conséquent celles-ci doivent être sérialisées. Mais si vous aviez deux commandes CREATE TABLE
, La suppression de l'une n'affecterait pas l'autre, donc ces deux commandes n'auraient pas à être sérialisées.
(Cette astuce ne s'applique pas à close()
cependant - la règle générale consiste à appeler uniquement close()
une fois que tout est terminé.)
J'ai trouvé cela dans la documentation SQLite :
la méthode Database # close s'exécutera toujours en mode exclusif, ce qui signifie qu'elle attend que toutes les requêtes précédentes soient terminées et que node-sqlite3 n'exécute aucune autre requête tant qu'une fermeture est en attente.
Il semble donc que la réponse à votre dernière question soit oui . Si vous n'avez qu'une seule requête à exécuter, il n'est pas nécessaire d'utiliser la fonction sérialiser. Vous n'avez pas à vous soucier de la fermeture de votre base de données avant la fin de la requête car SQLite est suffisamment intelligent pour ne pas le faire! :)