7.1 Aansluitpool

Vandaag gaan we nog professioneler leren werken met de database. En nu zullen we het hebben over de thread pool, of verbindingspool in het Engels.

Verbinding maken met de database duurt even. Vooral als de database op afstand is. Als we voor elk verzoek een verbinding maken met de database, zal de reactie van onze applicatie ongelooflijk traag zijn. Om nog maar te zwijgen over de middelen die het zal verbruiken.

Als oplossing voor dergelijke problemen werd voorgesteld om verbindingen met de basis op te slaan in een set, die de threadpool wordt genoemd.

Wanneer we een nieuwe verbinding aanvragen, maakt de verbindingspool deze aan en wanneer deze wordt gesloten, wordt deze niet gesloten, maar wordt deze opgeslagen in de verbindingspool. En als we opnieuw een verbinding aanvragen bij de verbindingspool, krijgen we een van de oude in plaats van een nieuwe te maken.

In feite werkt de applicatie via een speciale driver, die een wrapper is voor een gewone JDBC-driver en die extra functionaliteit heeft voor het werken met de pool. Deze situatie kan als volgt worden weergegeven:

verbinding zwembad

De programmeur kan de instellingen voor de verbindingspool handmatig instellen: het aantal actieve verbindingen, de time-out, enz.

Voor bijzonder extreme situaties kunt u uw eigen verbindingspool schrijven: een klasse die een lijst met verbindingen zal hebben. Het overschrijft de sluitfunctie, die de verbinding terugbrengt naar de lijst, en er zullen veel andere goodies zijn, zoals de timer voor open verbindingen. Wanneer er lange tijd geen verbinding is, wordt de verbinding verbroken.

7.2* Interface DataSource en ConnectionPoolDataSource

De threadpool werkt meestal samen met het DataSource-object. Dit object kan worden gezien als een abstractie van een database op afstand. De naam Data Source kan letterlijk vertaald worden als Data Source. Dat is een soort hint.

DataSource-objecten worden gebruikt om een ​​fysieke verbinding met een database te verkrijgen en zijn een alternatief voor DriverManager. Het is niet nodig om het JDBC-stuurprogramma te registreren. U hoeft alleen de juiste parameters in te stellen om een ​​verbinding tot stand te brengen envoer de methode getConnection() uit.

Bij het lokaal maken van een object van het type DataSource (rechtstreeks in de toepassing), worden de verbindingsparameters ingesteld volgens de juiste methoden die worden geleverd door de JDBC-stuurprogrammaprovider. Deze methoden worden niet gedefinieerd door de DataSource-interface, aangezien de parameters voor het verbinden met DBMS van verschillende leveranciers zowel in type als in aantal kunnen verschillen (niet alle DBMS vereisen bijvoorbeeld dat het type stuurprogramma of netwerkprotocol wordt opgegeven).

Als u dus met het Oracle DBMS werkt, is het voor het gebruik van de corresponderende set- en get-methoden noodzakelijk om een ​​object van het type OracleDataSource te verkrijgen, wat een instantie is van de klasse met dezelfde naam die de DataSource-interface implementeert. Daarom maakt deze manier van het maken van objecten van het type DataSource uw code minder draagbaar en minder afhankelijk van de specifieke implementatie van het stuurprogramma.

Het volgende is een codevoorbeeld dat het lokale gebruik illustreert van objecten van het type DataSource.

import java.sql.*;
import javax.sql.*;
import oracle.jdbc.driver.*;
import oracle.jdbc.pool.*;

public class DataSource {
    public static void main(String[] args) {
    	try {
        	OracleDataSource ods = new OracleDataSource();

        	ods.setUser("root");
        	ods.setPassword("secret");
        	ods.setDriverType("thin");
        	ods.setDatabaseName("test");
        	ods.setServerName("localhost");
        	ods.setPortNumber(1521);

        	Connection connection = ods.getConnection();
        	System.out.println("Connection successful!!!");

    	} catch (SQLException se) {
        	se.printStackTrace();
    	}
    	System.out.println("Goodbye!");
	}
}

7.3* JNDI-interface

De volledige mogelijkheden van objecten van het type DataSource komen tot uiting in combinatie met het gebruik van de JNDI-interface. JNDI is een speciale service (zoiets als een directory) voor grote servertoepassingen waarmee de ene service verbinding kan maken met de andere.

Met behulp van de naam- en directoryservice kunt u objecten opslaan van het type DataSource dat eerder door de systeembeheerder is gemaakt met vooraf gedefinieerde verbindingsparameters. Hieronder volgen enkele van de standaard eigenschapsnamen (parameternamen) die door Sun zijn ontwikkeld:

Eigendomsnaam Java-gegevenstype Doel
database naam Snaar Database naam
server naam Snaar Server naam
gebruiker Snaar Gebruikersnaam / ID)
wachtwoord Snaar Gebruikerswachtwoord
poortnummer int Poortnummer DBMS-server

De combinatie van DataSource- en JNDI-interfaces speelt een sleutelrol bij de ontwikkeling van multi-tier enterprise-applicaties op basis van J2EE-componenttechnologie.

Als u een combinatie van de DataSource- en JNDI-interfaces in uw applicatiecode gebruikt, hoeft u alleen een object van het type DataSource aan te vragen bij de naamgevings- en directoryservice. In dit geval worden de details van de verbinding en de programmacode die afhankelijk is van een bepaalde implementatie van het stuurprogramma verborgen voor de toepassing in het object dat is opgeslagen in de naam- en directoryservice.

Het delen van objecten van het type DataSource en JNDI omvat dus twee stappen die onafhankelijk van elkaar worden uitgevoerd:

  1. U moet het benoemde object van het type DataSource opslaan in de naamgevings- en directoryservice met behulp van Context.bind()de javax.naming.
  2. Vraag een object van het type DataSource aan bij de naamgevings- en directoryservice in de toepassing met behulp van de Context.lookup(). Daarna kunt u de methode gebruiken DataSource.getConnection()om verbinding te maken met de database.

Het volgende is een voorbeeld van het samen gebruiken van de JNDI-interface en een object van het type OracleDataSource.

// Create a key JNDI object
Hashtable env = new Hashtable();
env.put (Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory");
env.put (Context.PROVIDER_URL, "file:JNDI");
Context ctx = new InitialContext(env);

// Get the DataSource object by its name
DataSource ods = (DataSource) ctx.lookup("myDatabase");

// Get the Connection from the DataSource object
Connection connection = ods.getConnection();
System.out.println("Connection successful!!!");

We zullen het werk van JNDI niet analyseren. Dit valt buiten de scope van deze cursus. Ik wil alleen dat u weet dat deze aanpak heel gebruikelijk is bij grote toepassingen. Verdwaal niet als u in de toekomst dergelijke code ziet.

Het maakt niet uit hoe het werkt. U hoeft alleen maar te weten dat u met een JNDI-service het proxy-object kunt krijgen van elke service die is geregistreerd in de servicedirectory. Zo krijgt u het DataSource-object en gebruikt u het om met de database te werken.

7.4 Voorbeelden van aansluitpools

Laten we teruggaan naar waar we begonnen - verbindingspools.

Java-programmeurs gebruiken in hun programma's heel vaak bibliotheken die verschillende implementaties van verbindingspools bevatten. Onder hen zijn er drie het populairst:

  • Apache Commons DBCP
  • C3PO
  • HikariCP

Het Apache-project was het eerste dat een goede verbindingspool creëerde, het wordt ook gebruikt binnen de Tomcat-webserver. Een voorbeeld van ermee werken:

public class DBCPDataSource {

    private static BasicDataSource ds = new BasicDataSource();
    static {
    	ds.setUrl("jdbc:h2:mem:test");
    	ds.setUsername("user");
    	ds.setPassword("password");
    	ds.setMinIdle(5);
    	ds.setMaxIdle(10);
    	ds.setMaxOpenPreparedStatements(100);
    }

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

    private DBCPDataSource(){ }
}

De tweede zeer populaire pool is C3PO . Vreemde namen, ben ik met je eens. De naam C3PO is een verwijzing naar de c3po-robot uit Star Wars. En ook CP is een afkorting van Connection Pool.

public class C3p0DataSource {

    private static ComboPooledDataSource cpds = new ComboPooledDataSource();
    static {
    	try {
        	cpds.setDriverClass("org.h2.Driver");
        	cpds.setJdbcUrl("jdbc:h2:mem:test");
        	cpds.setUser("user");
        	cpds.setPassword("password");
    	} catch (PropertyVetoException e) {
            // handle the exception
    	}
    }

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

    private C3p0DataSource(){}
}

Documentatie hiervoor is te vinden op de officiële pagina .

En tot slot, de meest populaire Connection Pool in onze tijd is HikariCP :

public class HikariCPDataSource {

    private static HikariConfig config = new HikariConfig();
    private static HikariDataSource ds;

    static {
    	config.setJdbcUrl("jdbc:h2:mem:test");
    	config.setUsername("user");
    	config.setPassword("password");
    	config.addDataSourceProperty("cachePrepStmts", "true");
    	config.addDataSourceProperty("prepStmtCacheSize", "250");
    	config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
    	ds = new HikariDataSource(config);
    }

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

    private HikariCPDataSource(){}
}

Hier is zijn officiële GitHub- pagina .

En een goed artikel over configuratie.