2

如果有可能实现它,你能看看我的连接池吗?

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;

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

4

5 回答 5

6

有一些点使这个实现非常有问题。

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

我确信还有更多需要指出的地方,但除非这些都已修复,否则继续下去是没有用的。

于 2012-05-10T09:00:13.380 回答
5

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

解决这个问题的正常方法是使用委托包装返回的连接对象,并让它们忽略对 close 方法的调用(或者更好的是,让 close() 安全地将底层连接返回到池中)。

其他主要问题:

  • 如果在事务中间返回连接会发生什么?
  • 如果连接以某种方式损坏或断开连接会发生什么?它会留在游泳池里吗?

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

于 2012-05-10T09:08:18.537 回答
3

一些想法:

  • 您的代码不是线程安全的。也许在这方面工作。
  • getConnection() 中的代码过多。真的需要延迟初始化吗?
  • available 没用,可以用 pool.size() 代替。
于 2012-05-10T08:53:19.607 回答
2

AFAIK,

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

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

    此外,您还需要处理一些其他属性,例如connection timeout,purging 等,以使其适用于所有场景。

    使其线程安全。

于 2012-05-10T09:02:26.467 回答
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...");
    }
}

于 2020-02-07T13:47:11.073 回答