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:
- Kapcsolat megnyitása az adatbázissal az adatbázis-illesztőprogram segítségével
- TCP foglalat megnyitása az adatok olvasásához / írásához
- Adatok olvasása / írása a foglalaton keresztül
- A kapcsolat lezárása
- 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.