简体   繁体   中英

Java Connection Pool implementation

can you look at my connection pool if it is a possible way to implement it?

public class ConnectionPool {
    private static List<DBConnection> pool = null;
    private static int available = 0;
    private ConnectionPool() {}

    public static DBConnection getConnection() {
        if (pool == null) {
             pool = new ArrayList<DBConnection>();
             for (int i = 0; i < 3; i++) {
                 try {
                    pool.add(new DBConnection());
                    available++;
                } catch (SQLException e) {
                    e.printStackTrace();
                }
             }
        }
        if (pool.size() > 0) {
            available--;
            return pool.remove(available);
        } else {
            return null;
        }
    }

    public static void returnConnection(DBConnection c) {
        pool.add(c);
        available++;
    }
}

I'm using only one array and the client should ask the connection pool for a connection use it and then return it to the connection pool.

  Connection connection = ConnectionPool.getConnection();
  connection.execute("insert into users values('"+user.getUsername()+"', '"+user.getPassword()+"', '"+user.getGroup()+"', '"+banned+"', '"+broker+admin+sharehodler+company+"')");      
  ConnectionPool.returnConnection(connection);
  connection = null;

Please I need feedback on this implementation. Thank you

There are some points that make this implementation very problematic.

  • Thread safety. What if several threads work with the pool? You are not locking the list on read/write access.
  • Static maximum pool size of 3 connections, also you immediately create all of them, whether they are needed or not. A common strategy is to create a bunch of connections and create some more when needed, until the allowed/configured maximum is reached.
  • You only have static methods. It should be possible to have several pools, meaning you need instances of ConnectionPool .
  • No way to pass host+dbname+user+password to the connections that are created.
  • You don't deal with 'broken' connections - you may have to re-create a connection if an existing one screwed up. This is far more relevant than I thought before I started using pools.
  • Use config values instead of static values, see point #2
  • Lastly: sure, it's interesting to write this stuff yourself - but if you need a pool for a project, pick an existing one, such as c3p0 or the tomcat connection pool .

I'm sure there's more to point out, but unless these are fixed, there's no use in continuing.

One big problem with your pool implementation is that you pass the naked connection to the callers of the pool. This means that someone can obtain a connection from your pool, close it, and then return it to the pool. This is bad .

The normal way around this problem is to wrap the return connection objects using delegation, and make them ignore calls to the close method (or even better, make close() safely return the underlying connection to the pool).

Other major issues:

  • What happens if a connection is returned in the middle of a transaction?
  • What happens if a connection is somehow corrupted or disconnected? Does it stay in the pool?

All in all, you should reuse an existing connection pool implementation rather than writing your own. These days, many type 4 drivers have their own connection pools included right within the driver.

Some thoughts:

  • Your code is NOT thread safe. Maybe work on this.
  • Too much code in getConnection(). Is lazy initialisation really needed ?
  • available is useless, can be substitute by pool.size().

AFAIK,

  • your getConnection() method need to be changed to in order to retrieve Connection object only.

    Preparing connection and pooling should be taken away from the getConnection() method and added in such a way that when ConnectionPool class is loaded first time.

    Also you need to handle some other attributes as well like connection timeout , purging etc in order to make it work for all scenarios.

    Make it thread safe as well.

Other members have already suggested lots of things. I have some model implementation, thought of sharing it for new visitors. Here is code:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Iterator;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

abstract class ObjectPool<T> {
    private ConcurrentLinkedQueue<T> pool;
    ScheduledExecutorService executorService;

    ObjectPool(int minObjects) {
        pool = new ConcurrentLinkedQueue<T>();
        for (int i = 0; i < minObjects; i++) {
            pool.add(createObject());
        }
    }

    ObjectPool(final int minObjects, final int maxSize, final long interval){
        pool = new ConcurrentLinkedQueue<T>();
        for (int i = 0; i < minObjects; i++) {
            pool.add(createObject());
        }

        executorService = Executors.newSingleThreadScheduledExecutor();
        executorService.scheduleWithFixedDelay(new Runnable(){

            public void run() {
                int size = pool.size();
                while(size > maxSize){
                    pool.remove();
                }
                Iterator i = pool.iterator();
                while(i.hasNext()){
                    T t = (T) i.next();
                    if(checkExpiry(t)){
                        System.out.println("Expiry existed...");
                        i.remove();
                    }
                }

                while(pool.size() < minObjects){
                    System.out.println("Adding more objects to pool");
                    pool.add(createObject());
                }
            }

        }, interval, interval, TimeUnit.MILLISECONDS);

    }

    public T borrowObject() {
        if (pool.peek() == null)
            return createObject();
        return pool.remove();
    }

    public void addObject(T obj) {
        if (obj == null)
            return;
        pool.add(obj);
    }

    public abstract T createObject();

    public abstract boolean checkExpiry(T t);
}

class MultithreadQuery extends Thread{
    private ObjectPool<Connection> pool;
    private int threadNo;
    String query;
    MultithreadQuery(ObjectPool<Connection> pool,int threadNo, String query){
        this.pool = pool;
        this.threadNo = threadNo;
        this.query = query;

    }
    @Override
    public void run(){
        Connection con = pool.borrowObject();
        Statement stmt;
        try {
            stmt = con.createStatement();
            System.out.println("Query started for thread->"+ threadNo);
            ResultSet rs=stmt.executeQuery(query);
            while(rs.next())  
            System.out.println(rs.getInt(1)+"  "+rs.getString(2)+"  "+rs.getString(3));
            System.out.println("closing connection....");
            con.close();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }  
        pool.addObject(con);        
        System.out.println("Query ended for thread->"+ threadNo);
    }
}

public class ObjectPoolPatternDemo {
    ObjectPool<Connection> pool;

    public void setUp(){
        pool = new ObjectPool<Connection>(4, 10, 1) {

            @Override
            public Connection createObject() {
                Connection con;
                try {
                    con = DriverManager.getConnection("URL","Username","Password");
                    return con;
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                return null;
            }

            @Override
            public boolean checkExpiry(Connection conn) {
                boolean expiryFlag = false;
                try {
                    if(conn.isClosed())
                        expiryFlag = true;

                } catch (SQLException e) {
                    e.printStackTrace();
                }
                return expiryFlag;
            }
        };
    }

    public static void main(String[] args) throws SQLException {
        ObjectPoolPatternDemo oppd = new ObjectPoolPatternDemo();
        oppd.setUp();

        ExecutorService es = Executors.newFixedThreadPool(4);
        String query = "select * from TABLE";
        es.execute(new MultithreadQuery(oppd.pool,1,query));
        es.execute(new MultithreadQuery(oppd.pool,2,query));
        es.execute(new MultithreadQuery(oppd.pool,3,query));
        es.execute(new MultithreadQuery(oppd.pool,4,query));
        es.execute(new MultithreadQuery(oppd.pool,5,query));
        es.execute(new MultithreadQuery(oppd.pool,6,query));

        es.shutdown();
        try {
            es.awaitTermination(1, TimeUnit.DAYS);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("finally completed...");
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM