Heim > Java > javaLernprogramm > Was ist ein Hikari-Pool?

Was ist ein Hikari-Pool?

Mary-Kate Olsen
Freigeben: 2025-01-07 16:08:41
Original
953 Leute haben es durchsucht

O que é o hikari pool?

Was ist Hikari-Pool?

Diese einfache Frage in einem Beitrag auf BlueSky führte mich zu einer Erklärung, die ich wirklich cool fand. Ich bin hierher gekommen, um es zu Ende zu bringen.

In diesem speziellen Kontext wurde über den Hikari Connection Pool gesprochen. Aber wenn Hikari ein Verbindungspool ist, was wäre dann ein „Pool“?

Das Wichtigste zuerst: Poolkonzept

Bevor wir erklären, was HikariCP ist, müssen wir erklären, was ein Verbindungspool ist. Und um den Verbindungspool zu erklären, müssen wir den Pool erklären.

Sollen wir dafür eine ökonomische Analogie verwenden? Eine historische Wirtschaftsanalogie voller Fehler und Ungenauigkeiten mit der realen Welt, aber lassen Sie Ihren Unglauben schnell beiseite, nur um die Erklärung zu erhalten! Es ist in sich geschlossen.

Stellen Sie sich vor, Sie wären ein Herr/eine Dame im Mittelalter. Sie verfügen über die Werkzeuge, um die Arbeit der Bauern auszuführen. Und Sie möchten, dass sie funktionieren. Wie garantieren Sie dies? Gehören die Werkzeuge Ihnen? Sie müssen den Bauern ganz einfach die Werkzeuge liefern.

Stellen Sie sich also die Situation vor: Ihr Bauer braucht eine Hacke, um das Land zu jäten, also geht er dorthin und bittet Sie um eine Hacke. Du gibst ihm die Hacke und lebst weiter. Aber was ist mit seinem Hackenvorrat, wenn er es nicht zurückgibt? Eines Tages wird es enden...

Eine Alternative zur Abgabe der Hacke besteht darin, eine Hacke anfertigen zu lassen. Sie sind der Herr/die Herrin dieser Länder, also haben Sie Zugang zum Schmied, der das Metall in die Form einer Hacke schmelzen und in einen Griff einbauen kann. Aber das kann man nicht sofort produzieren, ohne dass der Bauer im Wartezimmer sitzt. Um diese neue Funktion zu erstellen, benötigen Sie enorm viel Zeit und Energie.

Wenn nun der Bauer die Hacke am Ende des Tages zurückgibt, steht sie am nächsten Tag einem anderen Bauern zur Verfügung.

Hier kontrollieren Sie den Pool von Hacken. Der Pool ist ein Entwurfsmuster, das angibt, dass Sie die folgenden Aktionen ausführen können:

  • Bitten Sie ihn um ein Element
  • Element dorthin zurückgeben

Andere häufige Dinge, die man in Pools von Objekten haben sollte:

  • Möglichkeit, bei Bedarf weitere Objekte zu erstellen, indem diese im Pool registriert werden
  • Fähigkeit, Objekte aus dem Pool zu zerstören (oder sie von diesem Pool zu trennen)

Herstellen einer Verbindung zur JDBC-Datenbank

Nun, kommen wir HikariCP näher. Lassen Sie uns hier über Datenbankverbindungen in Java sprechen.

In Java bitten wir darum, eine Verbindung zur Datenbank herzustellen. Es gibt die Direktverbindungsoption, bei der Sie direkt wissen müssen, welche Klassen aufgerufen werden sollen und einige Details, oder Sie nutzen einfach die Service-Discovery-Option.

Um die Service-Erkennung nutzen zu können, erstellt der Dienstanbieter a priori eine Möglichkeit, zu registrieren, was er bereitstellt, und dann geht die „Service-Erkennung“ danach, um zu sehen, wer diese Anfrage bedienen könnte.

Ein Fall von Diensterkennung: pstmt-null-safe

Ich hatte einen Fall, in dem ich JDBC-Verbindungen herstellen musste, um mit der Datenbank zu kommunizieren. Allerdings akzeptierte mein JDBC-Treiber die Verwendung von Nullen als Werten nicht, sondern nur Nullen direkt in Abfragen. Was habe ich also getan? Ein Fahrer auf einem Fahrer!

Die allgemeine Idee war die folgende. Stellen Sie sich vor, ich habe diese Abfrage, in die ich Werte einfügen möchte:

INSERT INTO some_table (id, content, parent)
VALUES (?, ?, ?)
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Stellen Sie sich nun vor, ich beschäftige mich mit der ersten Einzahlung dieses Wertes in die Bank. Dazu muss ich es bei ID=1, CONTENT=first und PARENT=null belassen, denn schließlich gibt es keinen übergeordneten Datensatz wie diesen (es ist schließlich der erste).

Was würde natürlich getan werden:

try (final var pstmt = conn.prepareStatement(
                """
                INSERT INTO some_table (id, content, parent)
                VALUES (?, ?, ?)
                """)) {

    pstmt.setInt(1, 1);
    pstmt.setString(2, "first");
    pstmt.setNull(3, Types.INTGEGER); // java.sql.Types
    pstmt.executeUpdate(); // de fato altere o valor
}
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Ich möchte es weiterhin so verwenden, schließlich ist es die idiomatische Art, es zu verwenden. Und laut CUPID kommt das „I“ von „idiomatisch“. Die Idee eines idiomatischen Codes besteht genau darin, „unnötige mentale Belastung zu reduzieren“.

Um dieses Problem zu lösen, habe ich mich entschieden: „prepareStatement“ bis zum letzten Moment vor „executeUpdate“ belassen. Also speichere ich alle anzuwendenden Nullen und wenn ich merke, dass ich tatsächlich eine Null benötige, führe ich eine String-Ersetzung durch und erzeuge eine neue Abfrage, und diese neue Abfrage wird tatsächlich ausgeführt.

In diesem Fall beginne ich mit:

INSERT INTO some_table (id, content, parent)
VALUES (?, ?, ?)
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Also muss ich diese Werte eingeben:

INSERT INTO some_table (id, content, parent)
VALUES (?, ?, ?)

-- 1, 'first', NULL
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Aber ich kann die Null nicht wirklich verwenden, also erstelle ich einen Schlüssel, um zu identifizieren, dass die dritte Stelle eine Null ist:

-- (value, value, NULL)
INSERT INTO some_table (id, content, parent)
VALUES (?, ?, NULL)
-- 1, 'first'
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Und in diesem Fall bereite ich diese neue Zeichenfolge vor und platziere die Argumente entsprechend den Anforderungen.

Okay, wie kann ich meiner Anwendung mitteilen, dass ich meinen JDBC-Treiber verwenden muss? Wie habe ich mich registriert?

Das fragliche Projekt ist Pstmt Null Safe. Grundsätzlich gibt es im Java-Klassenlader eine Magie, die beim Laden einer JAR-Datei nach einem Metadatenordner namens META-INF sucht. Und im Fall des JDBC-Treibers META-INF/services/java.sql.Driver, und ich habe es bei der Klasse notiert, die java.sql.Driver implementiert: br.com.softsite.pstmtnullsafe.jdbc.PstmtNullSafeDriver.

Laut der java.sql.Driver-Dokumentation sollte jeder Treiber eine Instanz von sich selbst erstellen und sich bei DriverManager registrieren. Ich habe es so umgesetzt:

INSERT INTO some_table (id, content, parent)
VALUES (?, ?, ?)
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Statischer Block lädt sich selbst. Und woher wissen wir, welche Verbindung mein Treiber verwalten soll? Der Aufruf erfolgt über DriverManager#getConnection(String url). Wir haben die URL, um den Treiber zu fragen, ob er die Verbindung akzeptiert. Die Konvention (auch hier die idiomatische Art, es zu verwenden) besteht darin, es dem URL-Schema voranzustellen. Da ich möchte, dass mein Treiber eine Verbindung zu einem anderen Treiber herstellt, habe ich das folgende Schema verwendet:

try (final var pstmt = conn.prepareStatement(
                """
                INSERT INTO some_table (id, content, parent)
                VALUES (?, ?, ?)
                """)) {

    pstmt.setInt(1, 1);
    pstmt.setString(2, "first");
    pstmt.setNull(3, Types.INTGEGER); // java.sql.Types
    pstmt.executeUpdate(); // de fato altere o valor
}
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Um die Tests durchzuführen, habe ich mich mit SQLite verbunden und den Xerial-Indikator verwendet, um eine In-Memory-Verbindung über den Verbindungs-URI anzufordern:

INSERT INTO some_table (id, content, parent)
VALUES (?, ?, ?)
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Um die Verbindung zu „umhüllen“, sieht meine Konvention vor, dass ich jdbc: nicht wiederhole, also:

INSERT INTO some_table (id, content, parent)
VALUES (?, ?, ?)

-- 1, 'first', NULL
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Analyse der obigen URI:

-- (value, value, NULL)
INSERT INTO some_table (id, content, parent)
VALUES (?, ?, NULL)
-- 1, 'first'
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Okay, und wie geben Sie das an? Die Driver#acceptsURL muss true zurückgeben, wenn ich die Verbindung öffnen kann. Ich könnte einfach Folgendes tun:

public static final PstmtNullSafeDriver instance;

static {
    instance = new PstmtNullSafeDriver();
    try {
        DriverManager.registerDriver(instance);
    } catch (SQLException e) {
        e.printStackTrace();
    }
}
Nach dem Login kopieren

Aber was würde das bedeuten, wenn ich versuchen würde, einen nicht vorhandenen Treiber zu laden? Nichts, es würde zu einem anderen Zeitpunkt ein Problem verursachen. Und das ist nicht gut, ideal wäre es, von Anfang an abzustürzen. Deshalb versuche ich, den Treiber von unten zu laden, und wenn das nicht gelingt, gebe ich false zurück:

jdbc:pstmt-nullsafe:<url de conexão sem jdbc:>
\__/ \____________/
 |    |
 |    Nome do meu driver
 Padrão para indicar JDBC
Nach dem Login kopieren

Der eigentliche Treibercode enthält einige weitere Punkte, die für die Diskussion hier über HikariCP, DataSource, JDBC oder die in diesem Beitrag behandelten Themen nicht relevant sind.

Wenn ich also eine „nullsichere“ Verbindung zu DriverManager anfordere, findet es zuerst meinen Treiber und mein Treiber versucht rekursiv zu prüfen, ob unter der Haube die Möglichkeit einer Verbindung besteht. Bestätigt, dass es einen Treiber gibt, der damit umgehen kann, sage ich ja, das ist möglich.

Das Verwendungsmuster von JDBC-Verbindungen in Java

Die Connection-Schnittstelle implementiert die AutoCloseable-Schnittstelle. Das heißt, Sie nehmen die Verbindung an, nutzen sie nach Belieben und schließen dann die Verbindung. Es ist ganz normal, dass Sie hiermit eine Indirektion verwenden oder, wenn Sie die Verbindung direkt verwenden, sie innerhalb eines try-with-resources:
-Blocks verwenden

jdbc:sqlite::memory:
Nach dem Login kopieren

Der Prozess des Herstellens von Verbindungen ist ein kostspieliger Prozess. Und auch der Service Discovery-Prozess ist nicht gerade kostenlos. Ideal wäre es also, den Treiber zu speichern, um dann die Verbindungen zu generieren. Lassen Sie uns dies nach und nach weiterentwickeln.

Zuerst benötigen wir ein Objekt, das wir mit dem Treiber starten können. Es kann leicht ein globales Objekt, eine injizierte Spring-Komponente oder etwas Ähnliches sein. Nennen wir es JdbcConnector:

jdbc:pstmt-nullsafe:sqlite::memory:
Nach dem Login kopieren

Eine mögliche Implementierung für getJdbcConnection() besteht darin, sich auf einen von dieser Funktion umfassten Zustand zu verlassen:

INSERT INTO some_table (id, content, parent)
VALUES (?, ?, ?)
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Bis jetzt läuft alles gut. Aber... erinnern Sie sich an das erste Beispiel, bei dem der Bauer im Werkzeugvorrat nach einer Hacke fragt? Also... Sollen wir das berücksichtigen? Anstatt die Verbindung tatsächlich zu schließen, können wir die Verbindung zum Pool wiederherstellen. Der Korrektheit halber werde ich vor mehreren gleichzeitigen Zugriffen schützen, aber ich mache mir hier keine Sorgen um die Effizienz.

Nehmen wir hier an, dass ich eine Klasse namens ConnectionDelegator habe. Es implementiert alle Connection-Methoden, führt jedoch keine eigenen Aktionen aus, sondern delegiert nur an eine Verbindung, die ihm als Konstruktor übergeben wird. Zum Beispiel für die Methode isClosed():

try (final var pstmt = conn.prepareStatement(
                """
                INSERT INTO some_table (id, content, parent)
                VALUES (?, ?, ?)
                """)) {

    pstmt.setInt(1, 1);
    pstmt.setString(2, "first");
    pstmt.setNull(3, Types.INTGEGER); // java.sql.Types
    pstmt.executeUpdate(); // de fato altere o valor
}
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Und so weiter für die anderen Methoden. Es ist abstrakt, weil ich mich dazu zwingen möchte, etwas anderes als eine einfache Delegation zu tun, wenn ich es verwende.

Nun, lass uns gehen. Die Idee ist, dass eine Verbindung angefordert wird, die möglicherweise vorhanden ist oder nicht. Wenn es existiert, schließe ich es in diese neue Klasse ein, damit ich es dann an pool zurückgeben kann, wenn ich die Verbindung schließe. Hmmm, also werde ich etwas in der close()-Methode tun ... Okay, packen wir es zuerst ein. Lassen wir getConnection() synchronisiert, um Parallelitätsprobleme zu vermeiden:

INSERT INTO some_table (id, content, parent)
VALUES (?, ?, ?)
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Ok, wenn ich Elemente im Pool von Verbindungen habe, verwende ich sie, bis er leer ist. Aber es ist nie gefüllt! Werden wir dieses Problem also lösen? Wenn es schließt, können wir es in den Pool zurückgeben!

INSERT INTO some_table (id, content, parent)
VALUES (?, ?, ?)

-- 1, 'first', NULL
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Ok, wenn Sie die Verbindung nicht mehr nutzen, wird sie an
zurückgesendet der Pool. Dies genügt nicht der Dokumentation für die Methode Connection#close(), da in der Dokumentation erwähnt wird, dass sie alle mit dieser Verbindung verbundenen JDBC-Ressourcen freigibt. Das bedeutet, dass ich alle Anweisungen, ResultSets, PreparedStatements usw. aufzeichnen müsste. Wir können damit umgehen, indem wir auf ConnectionDelegator eine geschützte Methode namens closeAllInnerResources() erstellen. Und rufen Sie es in close():
auf

-- (value, value, NULL)
INSERT INTO some_table (id, content, parent)
VALUES (?, ?, NULL)
-- 1, 'first'
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Und damit haben wir etwas, das bei Bedarf Verbindungen zu mir zurückgibt und das die Fähigkeit besitzt, einen Pool von Ressourcen zu bilden.

Wissen Sie, welchen Namen Java einem Objekt gibt, das Verbindungen bereitstellt? Datenquelle. Und wissen Sie, was Java sonst noch über DataSources zu sagen hat? Dass es konzeptionell gesehen einige Typen gibt. Und von diesen Typen sind die beiden relevantesten:

  • Grundlegend: Es führt kein Pooling durch, es wird nach einer Verbindung gefragt, es wird lediglich eine Verbindung erstellt und zurückgegeben
  • gepoolt: bei dem eine Bündelung der Verbindungen zur Bank erfolgt

Und hier durchlaufen wir den Prozess, immer wieder Verbindungen herzustellen (Grundtyp) und uns zu einer DataSource weiterzuentwickeln
gepoolt.

Was ist HikariCP?

HikariCP ist eine Datenquelle. Insbesondere eine gepoolte DataSource. Aber er hat eine Eigenschaft: Er ist der Schnellste von allen. Um diese Geschwindigkeit zu gewährleisten, macht HikariCP in seinem Pool von Verbindungen zur Verwendung während des Lebenszyklus der Anwendung ein Geheimnis: Es erstellt bereits alle verfügbaren Verbindungen. Wenn also eine getConnection eintrifft, muss HikariCP nur den Pool der Verbindungen überprüfen.

Wenn Sie tiefer in das Thema eintauchen möchten, können Sie sich diesen Artikel auf Baeldung zu diesem Thema sowie das Repository auf Github ansehen.

Das obige ist der detaillierte Inhalt vonWas ist ein Hikari-Pool?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:dev.to
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Neueste Artikel des Autors
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage