import java.sql.*; import java.util.*; public class DBConnectionPool { private int minconnections, // kapcsolatok kezdeti és minimális száma maxconnections; // kapcsolatok maximális száma private volatile Hashtable connections; // kapcsolatok táblázata. A kapcsolatok mint kulcsok használatosak. Ha szabad a kapcsolat, a tárolt érték megegyezik a kapcsolattal, különben a kapcsolatot felügyelô DBConnection-t tartalmazza private String url; // kapcsolat adatbázis URL-je private Properties props; // kapcsolat egyéb paraméterei private static final int TIMEOUT = 10 * 60 * 1000; // egy kapcsolat ennyi idô után autómatikusan felszabadul. Ha ez <= 0, nem indulnak el kapcsolatfelügyelô szálak. /** * Kapcsolatfelügyelô szál * Jelenleg egyetlen feladata a TIMEOUT letelte után a kapcsolat automatikus felszabadítása */ class DBConnection extends Thread { private Connection connection; // a felügyelt kapcsolat private long starttime; // létrehozás idôpontja DBConnection( Connection connection ) { super(); this.connection = connection; starttime = System.currentTimeMillis(); } public void run() { try { sleep( TIMEOUT ); freeConnection( connection ); // TIMEOUT letelte után a kapcsolat automatikus felszabadítása } catch ( Exception e ) {} } } /** * Rövid konstruktor * @param url : adatbázis URL * @param user : adatbáziskapcsolathoz használt felhasználói név * @param password : adatbáziskapcsolathoz használt felhasználói jelszó * @param minconnection : kapcsolatok kezdeti és minimális száma * @param maxconnection : kapcsolatok maximális száma */ public DBConnectionPool( String url, String user, String password, int minconnections, int maxconnections ) { props = new Properties(); if ( user != null ) props.put( "user", user ); if ( password != null ) props.put( "password", password ); this.url = url; this.minconnections = minconnections; this.maxconnections = maxconnections; } /** * Teljes konstruktor * @param url : adatbázis URL * @param props : kapcsolat egyéb paraméterei * @param minconnection : kapcsolatok kezdeti és minimális száma * @param maxconnection : kapcsolatok maximális száma */ public DBConnectionPool( String url, Properties props, int minconnections, int maxconnections ) throws SQLException { this.url = url; this.minconnections = minconnections; this.props = props; this.maxconnections = maxconnections; } /** * Kapcsolatok létrehozása * @throws : kapcsolatfelépítéskor esetleg fellépett SQLException */ public synchronized void connect() throws SQLException { if ( connections != null ) return; // már megvolt Hashtable cons = new Hashtable( maxconnections ); Connection connection; for ( int i = 0; i < minconnections; i++ ) { connection = DriverManager.getConnection( url, props ); cons.put( connection, connection ); // kezdetben szabadok a kapcsolatok } connections = cons; // minden kapcsolat megvan } /** * Kapcsolatok lezárása */ public synchronized void close() { Connection con; Object value; if ( connections == null ) return; // még nem volt connect for ( Enumeration e = connections.keys(); e.hasMoreElements(); ) try { con = (Connection)e.nextElement(); value = connections.get( con ); if ( value != con ) ((DBConnection)value).stop(); // felügyelôszál leállítása con.close(); } catch (Exception ex) {} connections.clear(); connections = null; } /** * Kapcsolat kérése * @return : a kért kapcsolat, vagy null, ha már nincs több szabad kapcsolat * @throws : kapcsolatfelépítéskor esetleg fellépett SQLException */ public synchronized Connection getConnection() throws SQLException { if ( connections == null ) return null; // még nem volt connect Connection con = null; for ( Enumeration cons = connections.keys(); cons.hasMoreElements(); ) { con = (Connection)cons.nextElement(); if ( connections.get( con ) == con ) break; // van még szabad kapcsolat con = null; } if ( con == null ) { // minden kapcsolat foglalt if ( connections.size() == maxconnections ) return null; // nem lehet több kapcsolatot létrehozni con = DriverManager.getConnection( url, props ); // új kapcsolat felvétele } DBConnection dbc = new DBConnection( con ); // felügyelô DBConnection szál létrehozása connections.put( con, dbc ); // kapcsolat foglaltságát jelzi if ( TIMEOUT > 0 ) dbc.start(); // felügyelô DBConnection szál indítása, ha kell return con; } /** * Kapcsolat elengedése * @param con : az elengedett kapcsolat * @throws : SQLException, ami a többletkapcsolatok leárása közben keletkezhet */ public synchronized void freeConnection( Connection con ) throws SQLException { if ( connections == null ) return; // még nem volt connect Object value = connections.get( con ); if ( value == null || value == con ) return; // ismeretlen vagy szabad kapcsolatot nem kell elengedni ((DBConnection)value).stop(); // felügyelô DBConnection szál megállítása if ( connections.size() > minconnections ) { // kapcsolat lezárása connections.remove( con ); con.close(); } else { // kapcsolat újra szabad connections.put( con, con ); } } /** * Foglalt kapcsolatok számának lekérdezése * @return : foglalt kapcsolatok száma */ public int countConnections() { if ( connections == null ) return 0; // még nem volt connect int ret = connections.size(); if ( ret > minconnections ) return ret; // minden kapcsolat foglalt Connection con; for ( Enumeration cons = connections.keys(); cons.hasMoreElements(); ) { con = (Connection)cons.nextElement(); if ( connections.get( con ) == con ) ret--; // még szabad a kapcsolat } return ret; } /** * Adott kapcsolat státuszának lekérdezése * @param con : a lekérdezett kapcsolat * @return : <0, ha nincs ilyen kapcsolat, 0 ha szabad a kapcsolat, különben a kapcsolat foglaltsági ideje ms-ban */ public long getStatus( Connection con ) { if ( connections == null ) return -1; // még nem volt connect Object value = connections.get( con ); if ( value == null ) return -1; // ismeretlen kapcsolat if ( value == con ) return 0; // szabad kapcsolat return System.currentTimeMillis() - ((DBConnection)value).starttime + 1; } /** * Kapcsolatok listázása * @return : aktuális kapcsolatok listája */ public Enumeration listConnections() { if ( connections == null ) return null; // még nem volt connect return connections.keys(); } }