Avatar billede jangravgaard Nybegynder
29. maj 2002 - 18:30 Der er 2 kommentarer og
1 løsning

singleton og connection pooling

Hej

Jeg har lavet min egen udgave af connection pooling vhj af en singleton klasse, men er ikke helt stærk idet. Det viser sig nemlig at når min system kører er der alt for mange processer(connections) i brug hos mysqladmin og det synes jeg jo ikke der skulle være.
Klassen skaber 10 connections fra starten af og opretter to lister med "free" og "busy" connections i, som så flyttes frem og tilbage under brug.

Jeg sørger for at der kun findes en udgave af min connectionpool klasse via min singleton klasse og min vector klasse bruges til mine to lister.
Desuden har jeg to klasser Respons og DBConnection, som hhv bruges til beskeder og selve kontakten til db og hvor jeg opretter mine connections på flg. måde

public DBConnection getConnection() {
    pooling.Singleton s = pooling.Singleton.getInstance();
    ConnectionPool pool = s.getConPool();
    DBConnection con = pool.getConnection();
    return con;
}
og
public boolean returnConnection(DBConnection db) {
    pooling.Singleton s = pooling.Singleton.getInstance();
    ConnectionPool pool = s.getConPool();
    pool.returnConnection(db);
    return false;
}

Er der nogen som kan finde fejlen??


package pooling;

import funktioner.*;
/**
* Insert the type's description here.
* Creation date: (15-05-2002 12:15:12)
* @author:
*/
public class ConnectionPool {

    private int min_poolsize = 10;
    private int cleanup = 200;
    private VectorListe free = new VectorListe(min_poolsize);
    private VectorListe busy = new VectorListe();
   
   
/**
* ConnectionPool constructor comment.
*/
public ConnectionPool() {
    init();
}

public void cleanUp()
{
    if (cleanup<free.size())
    {
        for (int i = 10;i<free.size();i++)
        {
            DBConnection db = (DBConnection)free.remove(i);
            db.closeAll();
            db = null;// let GarbageCollector do its work
        }
    }
}

public VectorListe getBusy() {
    return busy;
}

public DBConnection getConnection() {
    DBConnection db;
    if (!(free.size()==0))
    {
        db = (DBConnection)free.remove(1);
    }
    else
    {
        db = new DBConnection();
   
    }
    busy.add(db);
    return db;   
}

public VectorListe getFree() {
    return free;
}

public void init() {

    for (int i =0; i<min_poolsize;i++)
    {
        free.add(new DBConnection());
    }
}

public Respons returnConnection(DBConnection db) {

    boolean ok = busy.remove(db);
    free.add(db);
    cleanUp();
    if (ok)
    {
        return new Respons(11);
       
    }
    else
    {
          return new Respons(-15);
    }
}
}
---------------------------------------------------

package pooling;

public class Singleton
{
    static private Singleton instance;
    private java.lang.String testfelt;
    private static ConnectionPool conPool;
   
    //sikre at man IKKE kan bruge new()
    private Singleton()
    {   
        conPool = new ConnectionPool();
    }
   
    public synchronized static ConnectionPool getConPool() {
    return conPool;
    }
   
    static synchronized public Singleton getInstance()
    {
        if (instance == null)
        {
            instance = new Singleton();
        }
      return instance;
    }
   
    public java.lang.String getTestfelt() {
    return testfelt;
    }
   
    public void setTestfelt(java.lang.String newTestfelt) {
    testfelt = newTestfelt;
    }
}
-----------------------------------------------------
package pooling;


public class VectorListe extends java.util.Vector {

public VectorListe() {
    super();
}

public VectorListe(int initialCapacity) {
    super(initialCapacity);
}

public VectorListe(int initialCapacity, int capacityIncrement) {
    super(initialCapacity, capacityIncrement);
}

public VectorListe(java.util.Collection c) {
    super(c);
}
}

Avatar billede soelvpil Nybegynder
29. maj 2002 - 19:56 #1
Der er et par problemer, som måske kan være årsag til den uheldige opførsel.

1) En vektor er 0-baseret, d.v.s. det første element har indeks 0 og ikke 1. Ved getConnection returnerer du altid nummer 2 i listen, også hvis der kun er 1, det må da være en fejl?

2) En lille detalje: Din cleanUp løber fra index i=10. Skulle man være pernitten, burde du nok bruge variablen min_poolsize i stedet, da det nok er det antal du mener (så skal der kun rettes et sted).

3) Hvis man fjerner et element fra listen, skifter senere elementer i listen plads. Så hvis du fjerner elementet med index 10, får det element, der tidligere havde index 11 nu index 10, det element der tidligere havde index 12 får index 11 o.s.v. Det er du tilsyneladende ikke opmærksom på, i din cleanUp-metode
Avatar billede soelvpil Nybegynder
29. maj 2002 - 20:00 #2
I øvrigt er din VectorListe-klasse inderligt overflødig, den er jo fuldstændig magen til en Vector!
Avatar billede disky Nybegynder
29. maj 2002 - 23:18 #3
der er ingen grund til at have en liste for brugte og frie connectors,


p.s. brug denne klasse den er testet og virker helt sikkert:


lav en properties fil med f.eks. dette indhold:

# Sample ResourceBundle properties file
CMS.url=jdbc:mysql://SERVERNAME/DBNAME
CMS.user=BRUGERNAVN
logfile=LOG FIL PATH OG NAVNdrivers=org.gjt.mm.mysql.Driver
CMS.password=PASSWORD
CMS.maxconn=10

ret det med uppercase.

Jeg bruger den selv til flere projekter og den fungerer perfekt.



import java.io.*;
import java.sql.*;
import java.util.*;
import java.util.Date;

/**
* This class is a Singleton that provides access to one or many
* connection pools defined in a Property file. A client gets
* access to the single instance through the static getInstance()
* method and can then check-out and check-in connections from a pool.
* When the client shuts down it should call the release() method
* to close all open connections and do other clean up.
*/
public class DBConnectionManager
{
    static private DBConnectionManager instance;      // The single instance
    static private int clients;
   
    private Vector drivers = new Vector();
    private PrintWriter log;
    private Hashtable pools = new Hashtable();
   
    /**
    * Returns the single instance, creating one if it's the
    * first time this method is called.
    *
    * @return DBConnectionManager The single instance.
    */
    static synchronized public DBConnectionManager getInstance()
    {
        if (instance == null)
        {
            instance = new DBConnectionManager();
        }
        clients++;
        return instance;
    }
   
    /**
    * A private constructor since this is a Singleton
    */
    private DBConnectionManager()
    {
        init();
    }
   
    /**
    * Returns a connection to the named pool.
    *
    * @param name The pool name as defined in the properties file
    * @param con The Connection
    */
    public void freeConnection(String name, Connection con)
    {
        DBConnectionPool pool = (DBConnectionPool) pools.get(name);
        if (pool != null)
        {
            pool.freeConnection(con);
        }
    }
   
    /**
    * Returns an open connection. If no one is available, and the max
    * number of connections has not been reached, a new connection is
    * created.
    *
    * @param name The pool name as defined in the properties file
    * @return Connection The connection or null
    */
    public Connection getConnection(String name)
    {
        DBConnectionPool pool = (DBConnectionPool) pools.get(name);
        if (pool != null)
        {
            return pool.getConnection();
        }
        return null;
    }
   
    /**
    * Returns an open connection. If no one is available, and the max
    * number of connections has not been reached, a new connection is
    * created. If the max number has been reached, waits until one
    * is available or the specified time has elapsed.
    *
    * @param name The pool name as defined in the properties file
    * @param time The number of milliseconds to wait
    * @return Connection The connection or null
    */
    public Connection getConnection(String name, long time)
    {
        DBConnectionPool pool = (DBConnectionPool) pools.get(name);
        if (pool != null)
        {
            return pool.getConnection(time);
        }
        return null;
    }
   
    /**
    * Closes all open connections and deregisters all drivers.
    */
    public synchronized void release()
    {
        // Wait until called by the last client
        if (--clients != 0)
        {
            return;
        }
       
        Enumeration allPools = pools.elements();
        while (allPools.hasMoreElements())
        {
            DBConnectionPool pool = (DBConnectionPool) allPools.nextElement();
            pool.release();
        }
        Enumeration allDrivers = drivers.elements();
        while (allDrivers.hasMoreElements())
        {
            Driver driver = (Driver) allDrivers.nextElement();
            try
            {
                DriverManager.deregisterDriver(driver);
                log("Deregistered JDBC driver " + driver.getClass().getName());
            }
            catch (SQLException e)
            {
                log(e, "Can't deregister JDBC driver: " + driver.getClass().getName());
            }
        }
    }
   
    /**
    * Creates instances of DBConnectionPool based on the properties.
    * A DBConnectionPool can be defined with the following properties:
    * <PRE>
    * &lt;poolname&gt;.url        The JDBC URL for the database
    * &lt;poolname&gt;.user        A database user (optional)
    * &lt;poolname&gt;.password    A database user password (if user specified)
    * &lt;poolname&gt;.maxconn    The maximal number of connections (optional)
    * </PRE>
    *
    * @param props The connection pool properties
    */
    private void createPools(Properties props)
    {
        Enumeration propNames = props.propertyNames();
        while (propNames.hasMoreElements())
        {
            String name = (String) propNames.nextElement();
            if (name.endsWith(".url"))
            {
                String poolName = name.substring(0, name.lastIndexOf("."));
                String url = props.getProperty(poolName + ".url");
                if (url == null)
                {
                    log("No URL specified for " + poolName);
                    continue;
                }
                String user = props.getProperty(poolName + ".user");
                String password = props.getProperty(poolName + ".password");
                String maxconn = props.getProperty(poolName + ".maxconn", "0");
                int max;
                try
                {
                    max = Integer.valueOf(maxconn).intValue();
                }
                catch (NumberFormatException e)
                {
                    log("Invalid maxconn value " + maxconn + " for " + poolName);
                    max = 0;
                }
                DBConnectionPool pool =    new DBConnectionPool(poolName, url, user, password, max);
//                System.out.println("Poolname = "+poolName);
                pools.put(poolName, pool);
                log("Initialized pool " + poolName);
            }
        }
    }
   
    /**
    * Loads properties and initializes the instance with its values.
    */
    private void init()
    {
        InputStream is = getClass().getResourceAsStream("/db.properties");
        Properties dbProps = new Properties();
        try
        {
            dbProps.load(is);
        }
        catch (Exception e)
        {
            System.err.println("Can't read the properties file. Make sure db.properties is in the CLASSPATH");
            return;
        }
        String logFile = dbProps.getProperty("logfile", "DBConnectionManager.log");
        try
        {
            log = new PrintWriter(new FileWriter(logFile, true), true);
        }
        catch (IOException e)
        {
            System.err.println("Can't open the log file: " + logFile);
            log = new PrintWriter(System.err);
        }
        loadDrivers(dbProps);
        createPools(dbProps);
    }
   
    /**
    * Loads and registers all JDBC drivers. This is done by the
    * DBConnectionManager, as opposed to the DBConnectionPool,
    * since many pools may share the same driver.
    *
    * @param props The connection pool properties
    */
    private void loadDrivers(Properties props)
    {
        String driverClasses = props.getProperty("drivers");
        StringTokenizer st = new StringTokenizer(driverClasses);
        while (st.hasMoreElements())
        {
            String driverClassName = st.nextToken().trim();
            try
            {
                Driver driver = (Driver)
                Class.forName(driverClassName).newInstance();
                DriverManager.registerDriver(driver);
                drivers.addElement(driver);
                log("Registered JDBC driver " + driverClassName);
            }
            catch (Exception e)
            {
                log("Can't register JDBC driver: " + driverClassName + ", Exception: " + e);
            }
        }
    }
   
    /**
    * Writes a message to the log file.
    */
    private void log(String msg)
    {
        log.println(new Date() + ": " + msg);
    }
   
    /**
    * Writes a message with an Exception to the log file.
    */
    private void log(Throwable e, String msg)
    {
        log.println(new Date() + ": " + msg);
        e.printStackTrace(log);
    }
   
    /**
    * This inner class represents a connection pool. It creates new
    * connections on demand, up to a max number if specified.
    * It also makes sure a connection is still open before it is
    * returned to a client.
    */
    class DBConnectionPool
    {
        private int checkedOut;
        private Vector freeConnections = new Vector();
        private int maxConn;
        private String name;
        private String password;
        private String URL;
        private String user;
       
        /**
        * Creates new connection pool.
        *
        * @param name The pool name
        * @param URL The JDBC URL for the database
        * @param user The database user, or null
        * @param password The database user password, or null
        * @param maxConn The maximal number of connections, or 0
        *  for no limit
        */
        public DBConnectionPool(String name, String URL, String user, String password, int maxConn)
        {
            this.name = name;
            this.URL = URL;
            this.user = user;
            this.password = password;
            this.maxConn = maxConn;
        }
       
        /**
        * Checks in a connection to the pool. Notify other Threads that
        * may be waiting for a connection.
        *
        * @param con The connection to check in
        */
        public synchronized void freeConnection(Connection con)
        {
            // Put the connection at the end of the Vector
            freeConnections.addElement(con);
            checkedOut--;
            notifyAll();
            log("Free'ed 1 connection from " + name);
        }
       
        /**
        * Checks out a connection from the pool. If no free connection
        * is available, a new connection is created unless the max
        * number of connections has been reached. If a free connection
        * has been closed by the database, it's removed from the pool
        * and this method is called again recursively.
        */
        public synchronized Connection getConnection()
        {
            Connection con=null;
            if (freeConnections.size() > 0)
            {
                // Pick the first Connection in the Vector
                // to get round-robin usage
                con = (Connection) freeConnections.firstElement();
                freeConnections.removeElementAt(0);
                try
                {
                    if (con.isClosed())
                    {
                        log("Removed bad connection from " + name);
                        // Try again recursively
                        con = getConnection();
                    }
                }
                catch (SQLException e)
                {
                    log("Removed bad connection from " + name);
                    // Try again recursively
                    con = getConnection();
                }
            }
            else if (maxConn == 0 || checkedOut < maxConn)
            {
                con = newConnection();
            }
            if (con != null)
            {
                checkedOut++;
            }
            log("Taken 1 connection from " + name);
            return con;
        }
       
        /**
        * Checks out a connection from the pool. If no free connection
        * is available, a new connection is created unless the max
        * number of connections has been reached. If a free connection
        * has been closed by the database, it's removed from the pool
        * and this method is called again recursively.
        * <P>
        * If no connection is available and the max number has been
        * reached, this method waits the specified time for one to be
        * checked in.
        *
        * @param timeout The timeout value in milliseconds
        */
        public synchronized Connection getConnection(long timeout)
        {
            long startTime = new Date().getTime();
            Connection con;
            while ((con = getConnection()) == null)
            {
                try
                {
                    wait(timeout);
                }
                catch (InterruptedException e)
                {}
                if ((new Date().getTime() - startTime) >= timeout)
                {
                    // Timeout has expired
                    return null;
                }
            }
            log("Taken 1 connection from " + name);
            return con;
        }
       
        /**
        * Closes all available connections.
        */
        public synchronized void release()
        {
            Enumeration allConnections = freeConnections.elements();
            while (allConnections.hasMoreElements())
            {
                Connection con = (Connection) allConnections.nextElement();
                try
                {
                    con.close();
                    log("Closed connection for pool " + name);
                }
                catch (SQLException e)
                {
                    log(e, "Can't close connection for pool " + name);
                }
            }
            freeConnections.removeAllElements();
        }
       
        /**
        * Creates a new connection, using a userid and password
        * if specified.
        */
        private Connection newConnection()
        {
            Connection con = null;
            try
            {
                if (user == null)
                {
                    con = DriverManager.getConnection(URL);
                }
                else
                {
                    con = DriverManager.getConnection(URL, user, password);
                }
                log("Created a new connection in pool " + name);
            }
            catch (SQLException e)
            {
                log(e, "Can't create a new connection for " + URL);
                return null;
            }
            return con;
        }
    }
}
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester