Java连接池实现

时间:2012-05-10 08:49:08

标签: java database object connection pool

如果可以实现它,可以查看我的连接池吗?

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++;
    }
}

我只使用一个数组,客户端应该要求连接池使用连接,然后将其返回到连接池。

  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;

我需要有关此实施的反馈。谢谢

5 个答案:

答案 0 :(得分:6)

有一些观点使这种实现很成问题。

  • 线程安全。如果几个线程与池一起工作怎么办?您没有将列表锁定在读/写访问权限上。
  • 3个连接的静态最大池大小,您也可以立即创建所有这些连接,无论它们是否需要。一个常见的策略是创建一堆连接并在需要时创建更多连接,直到达到允许/配置的最大值。
  • 您只有静态方法。应该可以有多个池,这意味着您需要ConnectionPool
  • 的实例
  • 无法将host + dbname + user + password传递给创建的连接。
  • 您不处理'断开'连接 - 如果现有连接搞砸了,您可能需要重新建立连接。这比我开始使用池之前的想法更为重要。
  • 使用配置值而不是静态值,请参阅第2点
  • 最后:确定,自己编写这些内容很有意思 - 但如果您需要一个项目池,请选择现有项目,例如c3p0tomcat connection pool

我确信还有更多要指出的,但除非这些是固定的,否则继续没有用。

答案 1 :(得分:5)

池实现的一个大问题是您将裸连接传递给池的调用者。这意味着有人可以从池中获取连接,关闭它,然后将其返回池中。这是错误

解决此问题的常用方法是使用委托包装返回连接对象,并使它们忽略对close方法的调用(甚至更好,使close()安全地返回到池的底层连接。)

其他主要问题:

  • 如果在交易过程中返回连接会怎样?
  • 如果连接以某种方式损坏或断开连接会怎样?它留在游泳池吗?

总而言之,您应该重用现有的连接池实现,而不是自己编写。目前,许多类型4的驱动程序都在驱动程序中包含自己的连接池。

答案 2 :(得分:3)

一些想法:

  • 您的代码不是线程安全的。也许可以解决这个问题。
  • getConnection()中的代码太多。懒惰的初始化真的 需要吗?
  • 可用是无用的,可以用pool.size()替代。

答案 3 :(得分:2)

AFAIK,

  • 您的getConnection()方法需要更改为仅检索Connection对象。

    准备连接和池应该从getConnection()方法中删除,并以第一次加载ConnectionPool类时的方式添加。

    此外,您还需要处理其他一些属性,例如connection timeoutpurging等,以使其适用于所有情况。

    使其线程安全。

答案 4 :(得分:0)

其他成员已经提出了很多建议。我有一些模型实现,想与新访客共享。这是代码:

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...");
    }
}