Egyszerű útmutató a Java-kapcsolatok tárolásához

1. Áttekintés

A kapcsolati pooling egy jól ismert adatelérési minta, amelynek fő célja az adatbázis-kapcsolatok végrehajtásában és az adatbázis-olvasási / -írási műveletek költségeinek csökkentése.

Dióhéjban, a kapcsolati készlet a legalapvetőbb szinten az adatbázis-kapcsolat gyorsítótárának megvalósítása, amely meghatározott követelményeknek megfelelően konfigurálható.

Ebben az oktatóanyagban gyorsan összefoglaljuk néhány népszerű kapcsolat-pooling keretrendszert, és megtanuljuk, hogyan kell a semmiből megvalósítani saját kapcsolati készletünket.

2. Miért kell a Connection Pooling?

A kérdés természetesen retorikus.

Ha elemezzük egy tipikus adatbázis-kapcsolat életciklusának lépéseit, megértjük, miért:

  1. Kapcsolat megnyitása az adatbázissal az adatbázis-illesztőprogram segítségével
  2. TCP foglalat megnyitása az adatok olvasásához / írásához
  3. Adatok olvasása / írása a foglalaton keresztül
  4. A kapcsolat lezárása
  5. Az aljzat bezárása

Nyilvánvalóvá válik, hogy az adatbázis-kapcsolatok meglehetősen drága műveletek, és mint ilyen, minden lehetséges felhasználási esetben minimálisra kell csökkenteni (éles esetekben csak kerülni kell).

Itt jönnek létre a kapcsolat-pooling megvalósításai.

Egyszerűen csak egy adatbáziskapcsolat-tároló megvalósításával, amely lehetővé teszi számunkra a meglévő kapcsolatok újrafelhasználását, hatékonyan megtakaríthatjuk a rengeteg drága adatbázis-út végrehajtásának költségeit, ezáltal növelve az adatbázis-vezérelt alkalmazásaink általános teljesítményét.

3. JDBC Connection Pooling keretrendszerek

Pragmatikai szempontból a kapcsolatkészlet alapból történő megvalósítása csak értelmetlen, figyelembe véve az odakinn rendelkezésre álló „vállalati kész” kapcsolat-pooling keretek számát.

A didaktikai cikkből, amely a cikk célja, nem az.

Ennek ellenére, mielőtt megtanulnánk, hogyan kell megvalósítani egy alapvető kapcsolatkészletet, először mutassunk be néhány népszerű kapcsolatkészlet-keretet.

3.1. Apache Commons DBCP

Kezdjük ezt a gyors összefoglalót az Apache Commons DBCP Componenttel, egy teljes funkcionalitású, a JDBC keretrendszert összesítő kapcsolattal:

public class DBCPDataSource {private static BasicDataSource ds = new BasicDataSource (); statikus {ds.setUrl ("jdbc: h2: mem: teszt"); ds.setUsername ("felhasználó"); ds.setPassword ("jelszó"); ds.setMinIdle (5); ds.setMaxIdle (10); ds.setMaxOpenPreparedStatements (100); } public static Connection getConnection () dobja az SQLException {return ds.getConnection () -t; } privát DBCPDataSource () {}}

Ebben az esetben statikus blokkkal ellátott burkoló osztályt használtunk a DBCP tulajdonságainak egyszerű konfigurálásához.

Így szerezhet összevont kapcsolatot a DBCPDataSource osztály:

Connection con = DBCPDataSource.getConnection ();

3.2. HikariCP

Továbblépve nézzük meg a HikariCP-t, egy villámgyors JDBC kapcsolat-pooling keretrendszert, amelyet Brett Wooldridge készített (a HikariCP konfigurálásával és a lehető legtöbb kihasználásával kapcsolatos részletekért tekintse meg ezt a cikket):

public class HikariCPDataSource {private static HikariConfig config = new HikariConfig (); privát statikus HikariDataSource ds; statikus {config.setJdbcUrl ("jdbc: h2: mem: teszt"); config.setUsername ("felhasználó"); config.setPassword ("jelszó"); config.addDataSourceProperty ("cachePrepStmts", "true"); config.addDataSourceProperty ("prepStmtCacheSize", "250"); config.addDataSourceProperty ("prepStmtCacheSqlLimit", "2048"); ds = új HikariDataSource (config); } public static Connection getConnection () dobja az SQLException {return ds.getConnection () -t; } privát HikariCPDataSource () {}}

Hasonlóképpen, itt olvashatja el, hogyan lehet összevont kapcsolatot létrehozni a HikariCPDataSource osztály:

Connection con = HikariCPDataSource.getConnection ();

3.3. C3PO

Utolsó ebben a felülvizsgálatban a C3PO, egy erőteljes JDBC4 kapcsolat- és kimutatáskészítő keretrendszer, amelyet Steve Waldman fejlesztett ki:

public class C3poDataSource {private static ComboPooledDataSource cpds = new ComboPooledDataSource (); statikus {try {cpds.setDriverClass ("org.h2.Driver"); cpds.setJdbcUrl ("jdbc: h2: mem: teszt"); cpds.setUser ("felhasználó"); cpds.setPassword ("jelszó"); } catch (PropertyVetoException e) {// kezeli a kivételt}} public static Connection getConnection () dobja az SQLException {return cpds.getConnection (); } privát C3poDataSource () {}}

Ahogy az várható volt, összevont kapcsolat kialakítása a C3poDataSource osztály hasonló az előző példákhoz:

Connection con = C3poDataSource.getConnection ();

4. Egyszerű megvalósítás

Hogy jobban megérthessük a kapcsolatkészlet mögöttes logikáját, hozzunk létre egy egyszerű megvalósítást.

Kezdjük egy lazán összekapcsolt kialakítással, csak egyetlen felületen alapulva:

nyilvános felület ConnectionPool {Connection getConnection (); boolean releaseConnection (Csatlakozási kapcsolat); Karakterlánc getUrl (); Karakterlánc getUser (); String getPassword (); }

A ConnectionPool Az interfész meghatározza egy alap kapcsolati készlet nyilvános API-ját.

Most hozzunk létre egy megvalósítást, amely néhány alapvető funkciót biztosít, beleértve az összevont kapcsolat megszerzését és felszabadítását:

public class BasicConnectionPool megvalósítja a ConnectionPool {private String url; privát String felhasználó; privát karakterlánc jelszó; privát Lista connectionPool; private list usedConnections = new ArrayList (); privát statikus int INITIAL_POOL_SIZE = 10; public static BasicConnectionPool create (String url, String user, String password) dobja az SQLException {List pool = new ArrayList (INITIAL_POOL_SIZE); for (int i = 0; i <INITIAL_POOL_SIZE; i ++) {pool.add (createConnection (URL, felhasználó, jelszó)); } return new BasicConnectionPool (URL, felhasználó, jelszó, készlet); } // szabványos kivitelezők @Orride public Connection getConnection () {Connection connection = connectionPool .remove (connectionPool.size () - 1); usedConnections.add (kapcsolat); visszatérő kapcsolat; } @Orride public boolean releaseConnection (Connection connection) {connectionPool.add (connection); return usedConnections.remove (kapcsolat); } privát statikus kapcsolat createConnection (karakterlánc URL, karakterlánc felhasználó, karakterlánc jelszó) dobja az SQLException {return DriverManager.getConnection (url, felhasználó, jelszó); } public int getSize () {return connectionPool.size () + usedConnections.size (); } // standard getters}

Bár elég naiv, a BasicConnectionPool osztály biztosítja a minimális funkcionalitást, amit elvárhatunk egy tipikus kapcsolat-pooling megvalósítástól.

Dióhéjban az osztály inicializálja a kapcsolatkészletet egy Tömb lista 10 kapcsolatot tárol, amelyek könnyen felhasználhatók.

JDBC kapcsolatokat lehet létrehozni a DriverManager osztály és Datasource implementációkkal.

Mivel sokkal jobb fenntartani a kapcsolatok adatbázisának létrehozását agnosztikusan, az előbbit használtuk a teremt() statikus gyári módszer.

Ebben az esetben a metódust a BasicConnectionPool, mert ez az interfész egyetlen megvalósítása.

Összetettebb kivitelben, többféle ConnectionPool megvalósítások esetén előnyösebb lenne az interfészbe helyezni, így rugalmasabb kialakítást és nagyobb kohéziót kapunk.

A stressz szempontjából a legrelevánsabb pont itt az, hogy a medence létrehozása után a kapcsolatokat lekérjük a medencéből, így nincs szükség újak létrehozására.

Továbbá, amikor egy kapcsolat felszabadul, akkor az ténylegesen visszatér a készletbe, így más ügyfelek újra felhasználhatják.

Nincs további interakció az alapul szolgáló adatbázissal, például kifejezett hívás az A kapcsolat bezárult () módszer.

5. A BasicConnectionPool Osztály

Ahogy az várható volt, a mi felhasználásával BasicConnectionPool osztály egyértelmű.

Hozzunk létre egy egyszerű egységtesztet, és szerezzünk összesített memóriában lévő H2 kapcsolatot:

@Test public whenCalledgetConnection_thenCorrect () {ConnectionPool connectionPool = BasicConnectionPool .create ("jdbc: h2: mem: teszt", "felhasználó", "jelszó"); assertTrue (connectionPool.getConnection (). isValid (1)); }

6. További fejlesztések és refaktorálás

Természetesen bőven van hely a kapcsolat-pooling megvalósításunk jelenlegi funkcióinak módosítására / bővítésére.

Például átépíthetjük a getConnection () módszerrel, és adjon hozzá támogatást a maximális medence méretéhez. Ha az összes rendelkezésre álló kapcsolat megtörténik, és az aktuális készlet mérete kisebb, mint a beállított maximális méret, a módszer új kapcsolatot hoz létre.

Ezenkívül ellenőrizhetnénk, hogy a készletből kapott kapcsolat továbbra is él-e, mielőtt továbbítanánk az ügyfélnek.

@ A nyilvános kapcsolat felülbírálása A getConnection () az SQLException-t dobja {if (connectionPool.isEmpty ()) {if (usedConnections.size () <MAX_POOL_SIZE) {connectionPool.add (createConnection (URL, felhasználó, jelszó)); } else {dob új RuntimeException ("Elérte a maximális medence méretet, nincs elérhető kapcsolat!"); }} Csatlakozási kapcsolat = connectionPool .remove (connectionPool.size () - 1); if (! connection.isValid (MAX_TIMEOUT)) {connection = createConnection (URL, felhasználó, jelszó); } usedConnections.add (kapcsolat); visszatérő kapcsolat; } 

Vegye figyelembe, hogy a módszer most dob SQLEkivétel, vagyis frissítenünk kell a felület aláírását is.

Vagy hozzáadhatunk egy módszert a kapcsolatkészlet-példány kecses leállításához:

public void shutdown () dobja az SQLException {usedConnections.forEach (this :: releaseConnection); for (Csatlakozás c: connectionPool) {c.close (); } connectionPool.clear (); }

A gyártásra kész megvalósításokban a kapcsolatkészletnek egy csomó extra szolgáltatást kell nyújtania, például a jelenleg használt kapcsolatok nyomon követésének képességét, az előkészített utasítás-pooling támogatását és így tovább.

Mivel egyszerűvé tesszük a dolgokat, az egyértelműség kedvéért kihagyjuk ezeknek a további funkcióknak a megvalósítását és a megvalósítás szálbiztonságát.

7. Következtetés

Ebben a cikkben alaposan megvizsgáltuk, hogy mi is a kapcsolati pooling, és megtanultuk, hogyan lehet saját kapcsolat-pooling megvalósítást bevezetni.

Természetesen nem kell minden esetben a semmiből indulnunk, amikor egy teljes funkcionalitású kapcsolat-pooling réteget szeretnénk hozzáadni alkalmazásainkhoz.

Ezért készítettünk először egy egyszerű összesítést, amely bemutatja a legnépszerűbb csatlakozási készlet kereteit, így világos elképzelésünk lehet arról, hogyan kell velük dolgozni, és felvehetjük azt, amelyik a legjobban megfelel az igényeinknek.

Szokás szerint a cikkben bemutatott összes kódminta elérhető a GitHubon.