Tach!
Vorab muss ich mal etwas disclaimern: Mit dem sqlite3-Package habe ich keine Erfahrungen, ich entnehme meine hier präsentierten Erkenntnisse allein aus der Dokumentation und den allgemeinen Erfahrungen mit asynchronen Abläufen aus anderen JavaScript-Projekten. Was ich aber in der Dokumentation lese, klingt verständlich und plausibel, so dass ich stark annehme, zu wissen worauf es ankommt, wenn ich selbst das Paket verwenden wollte.
Begrifflichkeiten:
- sqlite3-Package: das npm-Paket als Wrapper um
- SQLite: die Library selbst.
Schlussfolgerung: Serialize-Modus einschalten. Aber auch dann musst du immer noch aufpassen. Die Funktionen arbeiten weiterhin asynchron und kehren sofort zurück...
D.h. man kommt nicht drumherum, die Dinge, die nacheinander ablaufen müssen, per Callback zu serialisieren?
Jein. Callbacks braucht man nur, wenn das Ergebnis der Aktion für den weiteren Verlauf wichtig ist. Ansonsten reicht es, die Aktionen im Serialize-Modus in die Warteschlange einzureihen und dann den Vorgang zu vergessen. Allerdings hat man unter Umständen ein Problem, wenn Fehler auftreten, denn die würden bei Verwendung eines Callback über diesen rückgemeldet. Ohne Callback würden sie aber geworfen werden, und das noch dazu zu einem unbestimmten Zeitpunkt. Ein try-catch um die Datenbankfunktionsaufrufe wird besonders die Exceptions der späten SQL-Commandos nicht fangen können, weil die Ausführung bereits an ganz anderer Stelle im Code angekommen ist.
Lösung für hmm müsste also sein, dass er INSERT_MITARBEITER und SELECT_USER_MITARBEITER nicht serialisieren muss, aber INSERT_USER_MITARBEITER, INSERT_SKILL und REPLACE_SKILL auf drei Callback Funktionen verteilt werden müssen?
Bei allen Inserts findet auf Seiten von SQLite ein Locking der gesamten Datenbank statt. Ob ein Select gefahrlos parallel abgeschickt werden kann und sich dann in eine SQLite-interne Warteschlange einreiht, weiß ich nicht. Ich weiß auch nicht, ob die im sqlite3-Package
Ich würde hier keinen Mischbetrieb von Database#serialize() und Database#parallelize() fahren wollen, weil mir das zu unübersichtlich wird und ich vermute, dass die Risiken den Vorteil der Parallelität nicht wert sind.
Ich kann mich noch nicht entscheiden, ob ich - jeweils innerhalb von Database#serialize() - eine Callback-Schlange aufbaue, in der sich sozusagen jedes Statement einreihen muss (vor allem, um Fehler direkt abfangen zu können) oder ob ich Statements ohne Ergebnis einfach so abschicken würde, und nur die, deren Ergebnis ich brauche, mit Callbacks versehe.
Definition Callback-Schlange: Jedes nachfolgende Statement muss innerhalb des Callbacks des vorhergehenden stattfinden.
Auf alle Fälle gibt das mit den Callbacks eine ziemliche Verschachtelung, die ich mit Promises entschärfen würde. Das sqlite3-Package hat keine eingebaute Promise-Chaining-Unterstützung, so dass man die zu verwendenden Funktionen selbst in jeweils einzelne Promises packen müsste. Dann kann statt Callback-Verschachtelung eine lineare .then()-Kette aufbauen.
Alles in allem nicht ganz einfach, aber die Kompliziertheit liegt hier in der Asynchronität des Geschehens. Generelles Wissen um Promises sind empfehlenswert. Sie sind hier zwar nicht nötig, und fügen einen weitere Komplexität hinzu, aber richtig angewendet kommt das der Lesbarkeit des Codes zugute.
let with = whatever;
do(something, with, function(with) {
do(something, with, function(with) {
do(something, with, function() {
...
});
});
});
let with = whatever;
do(something, with)
.then(function (with) {
return do(something, with)
})
.then(function (with) {
return do(something, with)
})
.then(function (with) {
return do(something, with)
});
Ohne Anspruch auf Exaktheit, es soll nur optisch zeigen, wie der Code ohne und mit Promises aussieht. Die Erstellung der eigentlichen Promises ist auch nicht enthalten. Die Variante ohne Promises sieht hier einfacher aus, aber das ändert sich noch, a) mit jeder neuen Ebene, b) wenn die Funktionen mit richtigem Inhalt gefüllt sind.
dedlfix.