Wie richte ich einen Verbindungspool in JDBC ein?

111

Kann jemand Beispiele oder Links zum Einrichten eines JDBC-Verbindungspools bereitstellen?

Bei der Suche in Google sehe ich viele verschiedene Möglichkeiten, dies zu tun, und es ist ziemlich verwirrend.

Letztendlich brauche ich den Code, um ein java.sql.ConnectionObjekt zurückzugeben, aber ich habe Probleme beim Einstieg. Alle Vorschläge sind willkommen.

Update: Haben javax.sqloder java.sqlhaben Sie keine Verbindungsimplementierungen? Warum wäre es nicht am besten, diese zu verwenden?

llm
quelle
8
Nein, Stock JDBC bietet kein Verbindungspooling. Dafür benötigen Sie eine separate Bibliothek. Die meisten App-Server und Servlet-Container enthalten Verbindungspools. Außerdem stellen die JPA-Implementierungen normalerweise auch Implementierungen bereit.
Will Hartung
3
Ein Update für moderne Java-Benutzer. JDBC 3.0+ (von dem ich glaube, dass es in Java 6 verwendet wird?) Hat eine Implementierung für gepoolte DB-Verbindungen. Java 7 verwendet JDBC 4 und Java 8 JDBC 4.1.
BRasmussen
1
In Bezug auf die JDBC 3.0-API für das Verbindungspooling: progress.com/tutorials/jdbc/jdbc-jdbc-connection-pooling
Arto Bendiken

Antworten:

102

Wenn Sie einen eigenständigen Verbindungspool benötigen, gehe ich lieber zu C3P0 als zu DBCP (das habe ich in dieser vorherigen Antwort erwähnt ). Ich hatte einfach zu viele Probleme mit DBCP unter hoher Last. Die Verwendung von C3P0 ist denkbar einfach. Aus der Dokumentation :

ComboPooledDataSource cpds = new ComboPooledDataSource();
cpds.setDriverClass( "org.postgresql.Driver" ); //loads the jdbc driver
cpds.setJdbcUrl( "jdbc:postgresql://localhost/testdb" );
cpds.setUser("swaldman");
cpds.setPassword("test-password");

// the settings below are optional -- c3p0 can work with defaults
cpds.setMinPoolSize(5);
cpds.setAcquireIncrement(5);
cpds.setMaxPoolSize(20);

// The DataSource cpds is now a fully configured and usable pooled DataSource 

Wenn Sie jedoch auf einem Anwendungsserver ausgeführt werden, würde ich empfehlen, den darin enthaltenen integrierten Verbindungspool zu verwenden. In diesem Fall müssen Sie es konfigurieren (siehe Dokumentation Ihres Anwendungsservers) und eine DataSource über JNDI abrufen:

DataSource ds = (DataSource) new InitialContext().lookup("jdbc/myDS");
Pascal Thivent
quelle
1
Das Gleiche gilt für das. Ich beobachte seit Jahren, wie DBCP unter Last blockiert. Version für Version.
Vasiliy
Ja, aber C3P0 auch, ich habe die beste Erfahrung mit BoneCP gemacht
Nicolas Mommaerts
1
Es sieht so aus, als ob BoneCP zugunsten von HikariCP veraltet ist . HikariCP wird auch in einer Antwort unten erwähnt .
Kaartic
19

Wenn Sie einen Verbindungspool benötigen, schreiben Sie normalerweise eine Anwendung, die in einer verwalteten Umgebung ausgeführt wird, dh Sie werden auf einem Anwendungsserver ausgeführt. Überprüfen Sie in diesem Fall unbedingt, welche Verbindungspooling-Funktionen Ihr Anwendungsserver bereitstellt, bevor Sie andere Optionen ausprobieren.

Die sofort einsatzbereite Lösung lässt sich am besten in die übrigen Funktionen des Anwendungsservers integrieren. Wenn Sie jedoch nicht auf einem Anwendungsserver ausgeführt werden, würde ich die Apache Commons DBCP-Komponente empfehlen . Es ist weit verbreitet und bietet alle grundlegenden Pooling-Funktionen, die die meisten Anwendungen benötigen.

Tendayi Mawushe
quelle
18

HikariCP

Es ist modern, es ist schnell, es ist einfach. Ich benutze es für jedes neue Projekt. Ich bevorzuge es viel gegenüber C3P0, kenne die anderen Pools nicht so gut.

tobijdc
quelle
18

Das Rad nicht neu erfinden.

Probieren Sie eine der sofort verfügbaren Komponenten von Drittanbietern aus:

  • Apache DBCP - Dieser wird intern von Tomcat und von Ihnen wirklich verwendet.
  • c3p0

Apache DBCP enthält ein anderes Beispiel zum Einrichten einer Pooling- Datei javax.sql.DataSource . Hier ist ein Beispiel , das Ihnen den Einstieg erleichtern kann.

Alexander Pogrebnyak
quelle
1
Es heißt C3P0. Es ist übrigens in Multithread-Umgebungen leistungsfähiger als DBCP, da DBCP den Zugriff auf einen einzelnen Thread sperrt.
BalusC
@ BalusC. Danke für die Korrektur, ich disclecsiahabe mich besiegt. Sie können sehen, dass der Link korrekt ist. :)
Alexander Pogrebnyak
1
@ Mudassir. Ich würde empfehlen, einen Drop-In-Ersatz für DBCP zu suchen, der von Spring zu Tomcat beigetragen hat -> static.springsource.com/projects/tc-server/2.0/admin/htmlsingle/… . Sie benötigen nicht den gesamten Tomcat-Server, um ihn zu verwenden, sondern nur ein einziges Glas tomcat-jdbc. Sie können es von Maven Central bekommen -> org.apache.tomcat:tomcat-jdbc:jar:7.0.22-> search.maven.org/…
Alexander Pogrebnyak
@ AlexanderPogrebnyak: Danke Alexander, das ist nett von dir. Ich plane, CP in einem Axis-Webdienst zu verwenden. Werde über deinen Vorschlag nachdenken. - Mudassir vor 7 Minuten
Mudassir
17

Ich würde empfehlen, die commons-dbcp- Bibliothek zu verwenden. Es sind zahlreiche Beispiele für die Verwendung aufgeführt. Hier ist der Link zum einfachen Verschieben . Die Verwendung ist sehr einfach:

 BasicDataSource ds = new BasicDataSource();
 ds.setDriverClassName("oracle.jdbc.driver.OracleDriver")
 ds.setUsername("scott");
 ds.setPassword("tiger");
 ds.setUrl(connectURI);
 ...
 Connection conn = ds.getConnection();

Sie müssen die Datenquelle nur einmal erstellen. Lesen Sie daher unbedingt die Dokumentation, wenn Sie nicht wissen, wie das geht. Wenn Sie nicht wissen, wie Sie JDBC-Anweisungen richtig schreiben, damit keine Ressourcen verloren gehen, sollten Sie auch diese Wikipedia- Seite lesen .

Eric Hauser
quelle
8
Erstellt dies tatsächlich einen Verbindungspool?
llm
@llm Sicher! Die javax.sql.DataSourceDefinition der Schnittstelle enthält eine Implementierung von "Connection Pooling" (außerdem denke ich, dass Sie bereits wissen, was eine JDBC-Schnittstelle ist)
Eddy
7

Auf dem App-Server, den wir dort verwenden, wo ich arbeite (Oracle Application Server 10g, wie ich mich erinnere), wird das Pooling vom App-Server ausgeführt. Wir rufen eine javax.sql.DataSourcemit einer JNDI-Suche mit a ab javax.sql.InitialContext.

es ist so etwas gemacht

try {     
   context = new InitialContext();
   jdbcURL = (DataSource) context.lookup("jdbc/CachedDS");
   System.out.println("Obtained Cached Data Source ");
}
catch(NamingException e)   
{  
    System.err.println("Error looking up Data Source from Factory: "+e.getMessage());
}

(Wir haben diesen Code nicht geschrieben, er wurde aus dieser Dokumentation kopiert .)

Powerlord
quelle
5

Schwimmbad

  • Durch den Pooling-Mechanismus können die Objekte im Voraus erstellt werden. Wenn eine Klasse geladen wird.
  • Es verbessert die Anwendung performance[Durch erneutes Verwenden derselben Objekte zum Ausführen von Aktionen für Objektdaten] und memory[Zuweisen und Aufheben der Zuweisung vieler Objekte führt zu einem erheblichen Speicherverwaltungsaufwand].
  • Eine Objektbereinigung ist nicht erforderlich, da wir dasselbe Objekt verwenden, wodurch die Garbage Collection-Last verringert wird.

«Pooling [ ObjectPool, Stringkonstanter Pool, ThreadPool, Verbindungspool]

String Konstanter Pool

  • Der String-Literal-Pool verwaltet nur eine Kopie jedes einzelnen String-Werts. das muss unveränderlich sein.
  • Wenn die interne Methode aufgerufen wird, überprüft sie die Objektverfügbarkeit mit demselben Inhalt im Pool mithilfe der Methode equals. «Wenn String-copy im Pool verfügbar ist, wird die Referenz zurückgegeben. «Andernfalls wird das String-Objekt zum Pool hinzugefügt und gibt die Referenz zurück.

Beispiel: Zeichenfolge zum Überprüfen des eindeutigen Objekts aus dem Pool.

public class StringPoolTest {
    public static void main(String[] args) { // Integer.valueOf(), String.equals()
        String eol = System.getProperty("line.separator"); //java7 System.lineSeparator();

        String s1 = "Yash".intern();
        System.out.format("Val:%s Hash:%s SYS:%s "+eol, s1, s1.hashCode(), System.identityHashCode(s1));
        String s2 = "Yas"+"h".intern();
        System.out.format("Val:%s Hash:%s SYS:%s "+eol, s2, s2.hashCode(), System.identityHashCode(s2));
        String s3 = "Yas".intern()+"h".intern();
        System.out.format("Val:%s Hash:%s SYS:%s "+eol, s3, s3.hashCode(), System.identityHashCode(s3));
        String s4 = "Yas"+"h";
        System.out.format("Val:%s Hash:%s SYS:%s "+eol, s4, s4.hashCode(), System.identityHashCode(s4));
    }
}

Connection Pool Typ-4 mit Treiber mit 3rd - Party - Bibliotheken [ DBCP2, c3p0, Tomcat JDBC]

Type 4 - The Thin driver converts JDBC calls directly into the vendor-specific database protocol Ex[Oracle - Thick, MySQL - Quora]. Wiki

Beim Verbindungspoolmechanismus werden beim Laden der Klasse die physical JDBC connectionObjekte abgerufen und dem Benutzer ein umschlossenes physisches Verbindungsobjekt bereitgestellt. PoolableConnectionist ein Wrapper um die eigentliche Verbindung.

  • getConnection()Wählen Sie eine der freien Wrapped -Verbindungen aus dem Verbindungsobjektpool aus und geben Sie sie zurück.
  • close() Anstatt zu schließen, wird die Wrapped-Verbindung wieder an den Pool zurückgegeben.

Beispiel: Verwenden des ~ DBCP2-Verbindungspools mit Java 7 [ try-with-resources]

public class ConnectionPool {
    static final BasicDataSource ds_dbcp2 = new BasicDataSource();
    static final ComboPooledDataSource ds_c3p0 = new ComboPooledDataSource();
    static final DataSource ds_JDBC = new DataSource();

    static Properties prop = new Properties();
    static {
        try {
            prop.load(ConnectionPool.class.getClassLoader().getResourceAsStream("connectionpool.properties"));

            ds_dbcp2.setDriverClassName( prop.getProperty("DriverClass") );
            ds_dbcp2.setUrl( prop.getProperty("URL") );
            ds_dbcp2.setUsername( prop.getProperty("UserName") );
            ds_dbcp2.setPassword( prop.getProperty("Password") );
            ds_dbcp2.setInitialSize( 5 );

            ds_c3p0.setDriverClass( prop.getProperty("DriverClass") );
            ds_c3p0.setJdbcUrl( prop.getProperty("URL") );
            ds_c3p0.setUser( prop.getProperty("UserName") );
            ds_c3p0.setPassword( prop.getProperty("Password") );
            ds_c3p0.setMinPoolSize(5);
            ds_c3p0.setAcquireIncrement(5);
            ds_c3p0.setMaxPoolSize(20);

            PoolProperties pool = new PoolProperties();
            pool.setUrl( prop.getProperty("URL") );
            pool.setDriverClassName( prop.getProperty("DriverClass") );
            pool.setUsername( prop.getProperty("UserName") );
            pool.setPassword( prop.getProperty("Password") );
            pool.setValidationQuery("SELECT 1");// SELECT 1(mysql) select 1 from dual(oracle)

            pool.setInitialSize(5);
            pool.setMaxActive(3);
            ds_JDBC.setPoolProperties( pool );
        } catch (IOException e) {   e.printStackTrace();
        } catch (PropertyVetoException e) { e.printStackTrace(); }
    }

    public static Connection getDBCP2Connection() throws SQLException {
        return ds_dbcp2.getConnection();
    }

    public static Connection getc3p0Connection() throws SQLException {
        return ds_c3p0.getConnection();
    }

    public static Connection getJDBCConnection() throws SQLException {
        return ds_JDBC.getConnection();
    }
}
public static boolean exists(String UserName, String Password ) throws SQLException {
    boolean exist = false;
    String SQL_EXIST = "SELECT * FROM users WHERE username=? AND password=?";
    try ( Connection connection = ConnectionPool.getDBCP2Connection();
          PreparedStatement pstmt = connection.prepareStatement(SQL_EXIST); ) {
        pstmt.setString(1, UserName );
        pstmt.setString(2, Password );

        try (ResultSet resultSet = pstmt.executeQuery()) {
            exist = resultSet.next(); // Note that you should not return a ResultSet here.
        }
    }
    System.out.println("User : "+exist);
    return exist;
}

jdbc:<DB>:<drivertype>:<HOST>:<TCP/IP PORT>:<dataBaseName> jdbc:oracle:thin:@localhost:1521:myDBName jdbc:mysql://localhost:3306/myDBName

connectionpool.properties

URL         : jdbc:mysql://localhost:3306/myDBName
DriverClass : com.mysql.jdbc.Driver
UserName    : root
Password    :

Webanwendung : Um Verbindungsprobleme zu vermeiden, wenn alle Verbindungen geschlossen sind [MySQL "wait_timeout" Standard 8 Stunden], um die Verbindung mit der zugrunde liegenden Datenbank wieder zu öffnen.

Sie können dies tun, um jede Verbindung zu testen, indem Sie testOnBorrow = true und validationQuery = "SELECT 1" setzen und autoReconnect für MySQL Server nicht verwenden, da es veraltet ist. Problem

===== ===== context.xml ===== =====
<?xml version="1.0" encoding="UTF-8"?>
<!-- The contents of this file will be loaded for a web application -->
<Context>
    <Resource name="jdbc/MyAppDB" auth="Container" 
        factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" 
        type="javax.sql.DataSource" 

        initialSize="5" minIdle="5" maxActive="15" maxIdle="10"

        testWhileIdle="true"
            timeBetweenEvictionRunsMillis="30000"

        testOnBorrow="true"
            validationQuery="SELECT 1"
            validationInterval="30000"


        driverClassName="com.mysql.jdbc.Driver" 
        url="jdbc:mysql://localhost:3306/myDBName" 
        username="yash" password="777"
    />
</Context>

===== ===== web.xml ===== =====
<resource-ref>
    <description>DB Connection</description>
    <res-ref-name>jdbc/MyAppDB</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
</resource-ref>
===== ===== DBOperations ===== =====
servlet «   init() {}
Normal call used by sevlet  « static {}

static DataSource ds;
static {
    try {
        Context ctx=new InitialContext();
        Context envContext = (Context)ctx.lookup("java:comp/env");
        ds  =   (DataSource) envContext.lookup("jdbc/MyAppDB");
    } catch (NamingException e) {   e.printStackTrace();    }
}

Siehe auch diese:

Yash
quelle
Im Beispiel für den Pool mit String-Konstanten verstehe ich, als Sie geschrieben haben: "Wenn String-copy im Pool verfügbar ist [.equals ()], wird die Referenz zurückgegeben." Andernfalls wird das String-Objekt zum Pool hinzugefügt und gibt die Referenz zurück. " Aber in der public class StringPoolTestnur hat 2 void Methoden, so dass sie nichts zurückgeben. Durchläuft dieser Code tatsächlich den Prozess der Verwaltung des Zeichenfolgenpools? Es scheint nicht einmal irgendwelche Argumente zu verwenden.
jeffery_the_wind
@jeffery_the_wind: - es ist nur das Pool - Konzept zu wissen, für String - Pool Überprüfung i nur verwendet hashCode, identityHashCode methodes . den Code geändert ...
Yash
Sorry, s1ist nicht definiert?
jeffery_the_wind
OK, ich wollte nur sicherstellen, dass ich alles sehe. Daran werde ich arbeiten. Was ich brauche, um etwas näher an deiner ConnectionPoolKlasse zu sein. Vielen Dank.
jeffery_the_wind
5

Ende 2017 sind Proxool, BoneCP, C3P0 und DBCP zu diesem Zeitpunkt größtenteils nicht mehr verfügbar. HikariCP (erstellt im Jahr 2012) scheint vielversprechend und sprengt die Türen von allem, was ich sonst noch weiß. http://www.baeldung.com/hikaricp

Proxool hat eine Reihe von Problemen:
- Unter hoher Last kann die maximale Anzahl von Verbindungen überschritten und nicht unter die maximale Anzahl zurückgegeben werden.
- Kann es schaffen, auch nach Ablauf der Verbindungen nicht zu minimalen Verbindungen zurückzukehren.
- Kann den gesamten Pool (und alle Server- / Client-Threads) sperren. Wenn während des HouseKeeper-Threads Probleme beim Herstellen einer Verbindung zur Datenbank auftreten (verwendet nicht .setQueryTimeout)
- Der HouseKeeper-Thread fordert den Prototyper-Thread auf, Verbindungen wiederherzustellen (Sweep), was zu Race Condition / Lockup führen kann. Bei diesen Methodenaufrufen sollte der letzte Parameter immer Sweep sein: false während der Schleife, nur Sweep: true darunter.
- HouseKeeper benötigt nur den einzelnen PrototypeController-Sweep am Ende und hat mehr [oben erwähnt]
- Der HouseKeeper-Thread prüft, ob Verbindungen getestet wurden, bevor festgestellt wird, welche Verbindungen möglicherweise abgelaufen sind [ein gewisses Risiko, abgelaufene Verbindungen zu testen, die durch andere Zeitüberschreitungen zur Datenbank in der Firewall unterbrochen / beendet werden können usw.]
- Das Projekt verfügt über unfertigen Code (definierte Eigenschaften) aber nicht bearbeitet )
- Die maximale Standardverbindungslebensdauer, falls nicht definiert, beträgt 4 Stunden (übermäßig)
- HouseKeeper-Thread wird alle fünf Sekunden pro Pool ausgeführt (übermäßig)

Sie können den Code ändern und diese Verbesserungen vornehmen. Da es 2003 erstellt und 2008 aktualisiert wurde, fehlen fast 10 Jahre Java-Verbesserungen, die Lösungen wie Hikaricp nutzen.

Bluejaguar
quelle
4

Wie von anderen beantwortet, werden Sie wahrscheinlich mit Apache Dbcp oder c3p0 zufrieden sein . Beide sind beliebt und funktionieren gut.

In Bezug auf Ihren Zweifel

Hat javax.sql oder java.sql keine gepoolten Verbindungsimplementierungen? Warum wäre es nicht am besten, diese zu verwenden?

Sie bieten keine Implementierungen, sondern Schnittstellen und einige Unterstützungsklassen, die nur den Programmierern zur Verfügung stehen, die Bibliotheken von Drittanbietern (Pools oder Treiber) implementieren. Normalerweise schaut man sich das gar nicht an. Ihr Code sollte die Verbindungen aus Ihrem Pool auf transparente Weise wie "einfache" Verbindungen behandeln.

leonbloy
quelle
4

Vibur DBCP ist eine weitere Bibliothek für diesen Zweck. Einige Beispiele zur Konfiguration für die Verwendung mit Hibernate, Spring + Hibernate oder programmgesteuert finden Sie auf der Website: http://www.vibur.org/

Siehe auch den Haftungsausschluss hier .

Simeon Malchev
quelle
3

Apache Commons verfügt zu diesem Zweck über eine Bibliothek: DBCP . Wenn Sie keine seltsamen Anforderungen an Ihre Pools haben, würde ich eine Bibliothek verwenden, da diese zwangsläufig schwieriger und subtiler ist, als Sie es sich erhoffen würden.

sblundy
quelle
1

Sie sollten die Verwendung von UCP in Betracht ziehen. Der Universal Connection Pool (UCP) ist ein Java-Verbindungspool. Es handelt sich um einen funktionsreichen Verbindungspool, der eng in die Real Application Clusters (RAC) -, ADG- und DG-Datenbanken von Oracle integriert ist.

Auf dieser Seite finden Sie weitere Informationen zu UCP.

Nirmala
quelle
0

MiniConnectionPoolManager ist eine One-Java-Datei-Implementierung, wenn Sie nach einer einbettbaren Lösung suchen und sich nicht zu sehr um die Leistung sorgen (obwohl ich sie diesbezüglich nicht getestet habe).

Es handelt sich um mehrfach lizenzierte EPL , LGPL und MPL .

Die Dokumentation enthält auch Alternativen, die es wert sind, überprüft zu werden (zusätzlich zu DBCP und C3P0):

Matthieu
quelle