7.1 Connection pool

Ngayon ay matututunan natin kung paano magtrabaho kasama ang database nang mas propesyonal. At ngayon ay pag-uusapan natin ang thread pool, o connection pool sa English.

Ang pagkonekta sa database ay tumatagal ng ilang oras. Lalo na kung malayo ang database. Kung gumawa kami ng isang koneksyon sa database para sa bawat kahilingan, kung gayon ang tugon ng aming aplikasyon ay magiging napakabagal sa bilis. Hindi banggitin ang mga mapagkukunang kukunin nito.

Bilang isang solusyon sa mga naturang problema, iminungkahi na mag-imbak ng mga koneksyon sa base sa ilang hanay, na tinatawag na thread pool.

Kapag humiling kami ng bagong koneksyon, nilikha ito ng pool ng koneksyon, at kapag sarado, hindi nito isinasara, ngunit ini-save ito sa pool ng koneksyon. At kung humiling muli kami ng koneksyon mula sa pool ng koneksyon, bibigyan kami nito ng isa sa mga luma sa halip na lumikha ng bago.

Sa katunayan, gumagana ang application sa pamamagitan ng isang espesyal na driver, na isang wrapper para sa isang regular na driver ng JDBC at kung saan ay may karagdagang pag-andar para sa pagtatrabaho sa pool. Ang sitwasyong ito ay maaaring ilarawan bilang mga sumusunod:

pool ng koneksyon

Maaaring itakda ng programmer ang mga setting para sa pool ng koneksyon nang manu-mano: ang bilang ng mga aktibong koneksyon, ang timeout, atbp.

Para sa mga partikular na matinding sitwasyon, maaari kang sumulat ng sarili mong connection pool: isang klase na magkakaroon ng listahan ng mga koneksyon. I-override nito ang close function, na magbabalik ng koneksyon pabalik sa listahan, at magkakaroon ng maraming iba pang goodies tulad ng open connection timer. Kapag walang koneksyon sa mahabang panahon, ang koneksyon ay sarado.

7.2* Interface DataSource at ConnectionPoolDataSource

Karaniwang gumagana ang thread pool kasabay ng object ng DataSource. Ang bagay na ito ay maaaring isipin bilang isang abstraction ng isang malayuang database. Ang mismong pangalan ng Data Source ay maaaring literal na isalin bilang Data Source. Which is kind of hinting.

Ang mga object ng DataSource ay ginagamit upang makakuha ng pisikal na koneksyon sa isang database at isang alternatibo sa DriverManager. Hindi na kailangang irehistro ang driver ng JDBC. Kailangan mo lamang itakda ang naaangkop na mga parameter upang magtatag ng isang koneksyon atisagawa ang getConnection() method.

Kapag gumagawa ng isang object ng uri ng DataSource nang lokal (direkta sa application), ang mga parameter ng koneksyon ay itinakda ng mga naaangkop na pamamaraan na ibinigay ng provider ng driver ng JDBC. Ang mga pamamaraang ito ay hindi tinukoy ng interface ng DataSource, dahil ang mga parameter para sa pagkonekta sa DBMS mula sa iba't ibang mga vendor ay maaaring magkaiba sa uri at sa bilang (halimbawa, hindi lahat ng DBMS ay nangangailangan ng uri ng driver o network protocol upang matukoy).

Kaya, kapag nagtatrabaho sa Oracle DBMS, upang magamit ang kaukulang hanay at makakuha ng mga pamamaraan, kinakailangan upang makakuha ng isang bagay ng uri ng OracleDataSource, na isang halimbawa ng klase ng parehong pangalan na nagpapatupad ng interface ng DataSource. Samakatuwid, ang ganitong paraan ng paglikha ng mga bagay na may uri ng DataSource ay ginagawang hindi gaanong portable ang iyong code at hindi gaanong nakadepende sa partikular na pagpapatupad ng driver.

Ang sumusunod ay isang halimbawa ng code na naglalarawan ng lokal na paggamit ng mga bagay na may uri ng 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* Interface ng JNDI

Ang buong kakayahan ng mga bagay na may uri ng DataSource ay ipinapakita kasama ng paggamit ng JNDI interface. Ang JNDI ay isang espesyal na serbisyo (tulad ng isang direktoryo) para sa malalaking application ng server na nagpapahintulot sa isang serbisyo na magtatag ng isang koneksyon sa isa pa.

Ang paggamit ng pangalan at serbisyo ng direktoryo ay nagbibigay-daan sa iyo na mag-imbak ng mga bagay ng uri ng DataSource na dati nang ginawa ng administrator ng system na may mga paunang natukoy na parameter ng koneksyon. Ang mga sumusunod ay ilan sa mga karaniwang pangalan ng property (parameter) na binuo ng Sun:

Pangalan ng ari-arian Uri ng data ng Java Layunin
databaseName String Pangalan ng database
pangalan ng server String Pangalan ng server
gumagamit String Username (ID)
password String Password ng user
portNumber int Numero ng port ng server ng DBMS

Ang kumbinasyon ng mga interface ng DataSource at JNDI ay gumaganap ng isang mahalagang papel sa pagbuo ng mga multi-tier na aplikasyon ng enterprise batay sa teknolohiyang bahagi ng J2EE.

Kung gagamit ka ng kumbinasyon ng mga interface ng DataSource at JNDI sa iyong application code, kailangan mo lang humiling ng object ng uri ng DataSource mula sa serbisyo ng pagbibigay ng pangalan at direktoryo. Sa kasong ito, ang mga detalye ng koneksyon at ang program code na nakasalalay sa isang partikular na pagpapatupad ng driver ay nakatago mula sa application sa bagay na nakaimbak sa pangalan at serbisyo ng direktoryo.

Kaya, ang pagbabahagi ng mga bagay ng uri ng DataSource at JNDI ay nagsasangkot ng dalawang hakbang na independiyenteng isinasagawa sa isa't isa:

  1. Dapat mong iimbak ang pinangalanang object ng uri ng DataSource sa serbisyo ng pagbibigay ng pangalan at direktoryo gamit Context.bind()ang javax.naming.
  2. Humiling ng isang object ng uri ng DataSource mula sa pagbibigay ng pangalan at serbisyo ng direktoryo sa application gamit ang Context.lookup(). Pagkatapos nito, maaari mong gamitin ang pamamaraan nito DataSource.getConnection()upang makakuha ng koneksyon sa database.

Ang sumusunod ay isang halimbawa ng paggamit ng JNDI interface at isang object ng uri ng OracleDataSource nang magkasama.

// 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!!!");

Hindi namin susuriin ang gawain ng JNDI. Ito ay nasa labas ng saklaw ng kursong ito. Gusto ko lang malaman mo na ang diskarteng ito ay karaniwan sa malalaking application. Huwag mawala kung makakita ka ng ganitong code sa hinaharap.

Hindi mahalaga kung paano ito gumagana. Kailangan mo lang malaman na sa isang serbisyo ng JNDI maaari mong makuha ang proxy object ng anumang serbisyo na nakarehistro sa direktoryo ng serbisyo. Ito ay kung paano mo makuha ang DataSource object at gamitin ito upang gumana sa database.

7.4 Mga Halimbawa ng Connection Pool

Bumalik tayo sa kung saan tayo nagsimula - mga pool ng koneksyon.

Ang mga programmer ng Java sa kanilang mga programa ay madalas na gumagamit ng mga aklatan na naglalaman ng iba't ibang mga pagpapatupad ng mga pool ng koneksyon. Kabilang sa mga ito mayroong tatlong pinakasikat:

  • Apache Commons DBCP
  • C3PO
  • HikariCP

Ang proyekto ng Apache ay ang unang lumikha ng isang mahusay na pool ng koneksyon, ginagamit din ito sa loob ng web server ng Tomcat. Isang halimbawa ng pagtatrabaho dito:

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(){ }
}

Ang pangalawang pinakasikat na pool ay C3PO . Kakaibang mga pangalan, sumasang-ayon ako. Ang pangalang C3PO ay isang reference sa c3po robot mula sa Star Wars. At din ang CP ay maikli para sa 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(){}
}

Ang dokumentasyon para dito ay matatagpuan sa opisyal na pahina .

At sa wakas, ang pinakasikat na Connection Pool sa ating panahon ay ang 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(){}
}

Narito ang kanyang opisyal na pahina ng GitHub .

At isang magandang artikulo sa pagsasaayos.