SQL Connection Pooling, Statements und Batching

  • Moin,


    ich bin noch recht unbewandert, was das Thema SQL Connection Pooling angeht. Ich bin bereits mit der grundlegenden Funktionsweise vertraut und kann, in meinem Fall, mit HikariCP arbeiten.

    Nun geht es mir aber darum, die richtige und optimalste Nutzweise zu verstehen/zu lernen. Ich bringe nachfolgendend mehrere Fragestellungen auf und würde mich über mehrere, gerne auch unterschiedliche, Meinungsbilder und Antworten eurerseits freuen!

    1. PreparedStatements vs Statements

    2. Up-/Download zur Datenbank

    2. Update-Methode

    3. Update-Interval (Verwendung von Batches)

    4. Redundanter Code


    Soo, das war es dann auch schon von meiner Seite. Vielen Dank an alle, die sich die Zeit genommen haben, sich meine Fragen durchzulesen!

    Ich heiße jede Hilfe, Hinweis und Tipp willkommen und würde mich auch um eine dazugehörende Erklärung freuen, damit ich mein Wissen erweitern und mich weiterbilden kann! Dies gilt natürlich auch für alle anderen, die diese Thematik interessieren oder sich ähnlich Fragen stellen.


    Vielen Dank!


    // EDIT: Ich merke gerade, dass ich im falschen Bereich des Forums gelandet bin. Vielleicht könnte ja ein Mod das Thema in den richtigen Bereich verschieben. Sorry dafür!

  • Sollte ich für einmalige SQL-Tasks auch PreparedStatements nutzen oder ist es besser die normalen Statements zu nutzen?

    Wie sieht es von der Performance bei einmaliger Verwendung aus? Gibt es eine grundlegende Faustregel, wann was genutzt werden sollte?

    Genau kann ich dir diese Frage nicht beantworten. Für meinen Teil würde ich aber immer Prepared Statements in Betracht ziehen, allein schon aus dem Grund, wie du selber sagtest, um SQL Injections zu vermeiden.


    Soweit ich das gerade richtig interpretiere, werden "normale" Statements ebenfalls compiled, so wie PreparedStatements, nur mit dem Unterschied, dass Prepared Statements gecached werden, so also eine schnellere Ausführung bei weiteren Aufrufen dieser erfolgen kann. Performance-technisch dürften sich Prepared Statements meines Erachtens nach also nicht großartig viel gegenüber "normalen" Statements geben, zumindest bei einmaliger Ausführung :)

  • Okay danke, alles klar. Werde ich so machen!


    Aber theoretisch gesehen sind ja nicht alle Statements/Queries anfällig für SQL Injections. Genauer gesagt sind es ja nur die, die direkte Inputs von Spielern annehmen.

    CREATE TABLE `stats`(`uuid` VARCHAR(36), etc...);

    UPDATE `stats` SET `kills`=? WHERE `uuid`=?; (hier nutze ich aufgrund der Parametisierung sowieso PreparedStatements)


    Aber eigentlich sind beide Statements nicht anfällig, da das erste ja komplett statisch ist und beim zweiten die Stats an sich sowie die UUID ja keine SQL Befehle enthalten können und ja auch vom Plugin eingetragen werden. Theoretisch ist somit also auch jedes System mit einem Cache sicher vor SQL Injections. (sofern die Spieler per Befehl immer nur Requests an den Cache, wie z.B. ein Stats Objekt schicken)

    Sehe ich da irgendwas falsch oder funktioniert das in der Praxis auch so, wie ich es mir jetzt theoretisch vorgestellt habe?



    Ich hätte dann doch nochmal eine Frage:

    Mir wurde mal gesagt, dass man das ResultSet nicht durch ein Callback oder CompletableFuture aus der eigentlichen Methode rausholen sollte. Wieso ist das so?

  • Aber theoretisch gesehen sind ja nicht alle Statements/Queries anfällig für SQL Injections. Genauer gesagt sind es ja nur die, die direkte Inputs von Spielern annehmen.

    Das stimmt. Ich verwende zumindest in der Webentwicklung trotzdem immer Prepared Statements. Vielleicht auch, um solche Anfragen immer einheitlich zu haben, also den Code zum Anfragen. Ich werde durch das WSC aber auch dazu gezwungen, da deren Database-API nur noch Prepared Statements unterstützt.


    Aber wie oben erwähnt, nehmen sich Prepared Statements und normale Statements bei einmaliger Ausführung scheinbar nichts.


    Bei dem Rest kann ich dir nicht helfen, habe noch nicht mit Datenbanken in Java gearbeitet.

  • Ich habe momentan leider nicht so viel Zeit um hier eine große Antwort zu schreiben, bei der ich alle der genannten Fragen beantworte, ich würde dir aber dennoch gerne helfen, gerade auch, weil du dir viel Mühe gegeben hast, deine Fragen/Probleme ausführlich zu erläutern.


    Deshalb würde ich dir anbieten die Punkte ggf. in einem Gespräch in Teamspeak/Discord zu erläutern. Voraussetzung für dieses Angebot wäre allerdings, dass du dann im Anschluss die Aspekte auch hier schriftlich festhältst, damit auch allen Anderen, die im Nachhinein über dieses Thema stolpern, geholfen ist.


    Hättest du daran Interesse?

  • Ich verwende zumindest in der Webentwicklung trotzdem immer Prepared Statements.

    Ja stimmt, in der Webentwicklung verläuft das ganze ja noch ein bisschen anders und Userinput kommt recht häufig vor.

    Vielen Dank dir aber trotzdem für deine Hilfe!


    Scrayos ja das Angebot würde ich gerne annehmen und selbstverständlich teile ich meine Ergebnisse anschließend in diesem Thema.




    Nachdem ich nun ein sehr interessantes und aufschlussreiches Gespräch mit Scrayos geführt habe, vielen lieben Dank an dich nochmal <3 , kann ich jetzt meine Fragen beantworten.

    Um auch möglichen Interessenten weiterzuhelfen, teile ich mit euch mein neu erlentes Wissen bezüglich meiner zuvor gestellten Fragen.

    1. PreparedStatements vs Statements

    Prinzipiell sollten in fast allen Fällen PreparedStatements verwendet werden. Diese werden vom Datenbankserver prepared und gecached und können bei mehrmaliger Nutzung wiederverwendet werden. Dies gilt auch für Statements, die sich ähnlich sind und in nur wenigen Punkten unterscheiden. (z.B. zwei ähnliche SELECT...-Statements) Bei einmaliger Nutzung lassen sich keine Performanceeinbuße gegenüber normalen Statements aufweisen. Zudem sollten einmalige Statements, wie z.B. ein CREATE TABLE....-Statement, durch Implementierungen wie Flyway umgesetzt werden, da diese spätere Änderungen an der Datenbankstruktur vereinfacht ermöglichen.

    2. Up-/Download zur Datenbank

    Meine bereits vorgestellte Herangehensweise ist schon ein gute Vorgehensweise. Man könnte sich noch überlegen, dass man Änderungen weiterhin im Cache behält aber auch zusätzlich direkt an die Datenbank sendet. Dabei sollte man hauptsächlich nur die Daten cachen, die auch regelmäßig abgerufen werden müssen. Daten, die nicht so oft gebraucht werden, müssen nicht unbedingt gecached werden und können dann bei Bedarf abgerufen werden. Dadurch kann, vor allem bei großen Datensätzen, Speicherplatz gespart werden.

    Was mir nicht ganz so bewusst gewesen ist, dass dataSource.getConnection() nicht zwingend eine neue Connection erstellt, sondern eine verfügbare Connection aus dem Pool holt. Es wird nur eine neue erstellt, sofern keine weitere Connection frei ist und das Limit des Pools noch nicht erreicht ist.

    Wenn man asynchron mit Datenbanken arbeitet, sollte man die Nutzung von einem Latch in Erwägung ziehen, um sicherzugehen, dass die Daten auch gespeichert wurden, bevor z.B. der Spieler den Server verlassen hat.

    3. Update-Methode

    Meine verwendete Update-Methode ist ebenfalls schon eine gute Herangehensweise, kann an einigen Stellen jedoch noch angepasst werden.

    Die Statements müssen nicht zwingend in die Klammern des try-with-resources-Block, da diese automatisch geschlossen werden, wenn die Connection geschlossen wird.

    Zudem sollten die Statements nur dann prepared werden, wenn diese tatsächlich benötigt werden. Außerdem kann man die UUID anstelle eines VARCHARS auch als BINARY in der Datenbank abspeichern. Dafür muss diese jedoch zunächst in einen byte-Array umgewandelt werden.

    Überarbeitete Methode:

    4. Update-Interval

    Hier verhält es sich ziemlich ähnlich wie bei der anderen Methode.

    5. Redundanter Code

    Mein Problem mit dem Redundanten Problem habe ich vorerst wie folgt gelöst. Dadurch kann ich entweder einen einzelnen User oder gleich mehrere auf einmal angeben.


    Vielleicht können die Antworten ja nicht nur mir weiterhelfen und der ein oder andere kann auch noch etwas dazulernen.

    Natürlich sind weitere Anmerkungen stets willkommen!


    Vielen Dank ilou und Scrayos , dass ihr euch dem Thema angenommen habt!

    Wenn sich jetzt bei der Erklärung Fehler eingeschlichen haben, dürft ihr gerne auf diese hinweisen.


    Viele Grüße!

    2 Mal editiert, zuletzt von NichtShady () aus folgendem Grund: Ein Beitrag von NichtShady mit diesem Beitrag zusammengefügt.