需要代码在java中创建连接池

Posted

技术标签:

【中文标题】需要代码在java中创建连接池【英文标题】:Need Code to create Connection Pool in java 【发布时间】:2011-02-19 01:14:49 【问题描述】:

需要在java中创建连接池的代码吗? 我们如何确保连接池不会返回已在使用的相同对象? 如果客户端从连接池中取出连接后关闭连接会怎样?

更新 1:

我想用简单的 Java 术语创建它,并想看看它在多线程环境中是如何工作的。我的意思是哪些方法会被同步,哪些不是。这门课也会是公共课吗?如果是,那么任何人都可以访问这个类并重新初始化连接池?

更新 2:

我有一些代码如下。但我不知道“关闭来自池的连接会将其返回到池中,它不会物理关闭连接。” 我也不明白这个“因为如果从池中借用连接但尚未返回,则它不是“可用”并且不能重新分配给池的另一个客户端。”

import java.util.*;
import java.sql.*;

class ConnectionPoolManager


 String databaseUrl = "jdbc:mysql://localhost:3306/myDatabase";
 String userName = "userName";
 String password = "userPass";

 Vector connectionPool = new Vector();

 public ConnectionPoolManager()
 
  initialize();
 

 public ConnectionPoolManager(
  //String databaseName,
  String databaseUrl,
  String userName,
  String password
  )
 
  this.databaseUrl = databaseUrl;
  this.userName = userName;
  this.password = password;
  initialize();
 

 private void initialize()
 
  //Here we can initialize all the information that we need
  initializeConnectionPool();
 

 private void initializeConnectionPool()
 
  while(!checkIfConnectionPoolIsFull())
  
   System.out.println("Connection Pool is NOT full. Proceeding with adding new connections");
   //Adding new connection instance until the pool is full
   connectionPool.addElement(createNewConnectionForPool());
  
  System.out.println("Connection Pool is full.");
 

 private synchronized boolean checkIfConnectionPoolIsFull()
 
  final int MAX_POOL_SIZE = 5;

  //Check if the pool size
  if(connectionPool.size() < 5)
  
   return false;
  

  return true;
 

 //Creating a connection
 private Connection createNewConnectionForPool()
 
  Connection connection = null;

  try
  
   Class.forName("com.mysql.jdbc.Driver");
   connection = DriverManager.getConnection(databaseUrl, userName, password);
   System.out.println("Connection: "+connection);
  
  catch(SQLException sqle)
  
   System.err.println("SQLException: "+sqle);
   return null;
  
  catch(ClassNotFoundException cnfe)
  
   System.err.println("ClassNotFoundException: "+cnfe);
   return null;
  

  return connection;
 

 public synchronized Connection getConnectionFromPool()
 
  Connection connection = null;

  //Check if there is a connection available. There are times when all the connections in the pool may be used up
  if(connectionPool.size() > 0)
  
   connection = (Connection) connectionPool.firstElement();
   connectionPool.removeElementAt(0);
  
  //Giving away the connection from the connection pool
  return connection;
 

 public synchronized void returnConnectionToPool(Connection connection)
 
  //Adding the connection from the client back to the connection pool
  connectionPool.addElement(connection);
 

 public static void main(String args[])
 
  ConnectionPoolManager ConnectionPoolManager = new ConnectionPoolManager();
 


【问题讨论】:

不管下面的一些答案是什么,都写你自己的连接池。将您与周围的其他人进行比较,并在此过程中了解更多有关 JDBC 和其他内容的知识。仅仅拥有一堆成熟的产品不应该阻止你制作自己的产品。只需将它们视为要被击败的标准。去吧 【参考方案1】:

使用现有的之一,例如Apache DBCP

池返回的连接通常是“忽略”应用程序对close() 的调用的代理。当连接返回到池中时,它们可以被重用。如有必要,游泳池也会自动关闭和重新打开。

【讨论】:

【参考方案2】:

需要在java中创建连接池的代码吗?

不确定问题是什么,但不要创建另一个连接池,使用现有的解决方案,如 C3P0、Apache DBCP、Proxool 或 BoneCP(该领域的新玩家)。我会使用 C3P0。

我们如何确保连接池不会返回已在使用的同一个对象?

因为如果一个连接已经从池中借用并且还没有返回,它只是不在池中并且不能分配给池的另一个客户端(资源被从池中移除直到它们被返回)。

如果客户端从连接池中取出连接后关闭连接会怎样?

客户端从池中获得的连接并不是真正的java.sql.Connection,它是java.sql.Connection 的包装器(代理),可自定义某些方法的行为。 close() 方法就是其中之一,它关闭 Connection 实例,而是将其返回到池中。

【讨论】:

+1 for C3PO...我一直在使用它,效果非常好。它重量轻,非常易于使用。 “不关闭 Connection 实例,而是将其返回到池中” - 连接类如何知道池并在调用 close 方法时能够将自身返回到池中? 请务必查看 Hikari CP:github.com/brettwooldridge/HikariCP。从我读到的,它似乎比列出的要快得多。【参考方案3】:

如果您的应用程序在服务器上运行,则配置为数据源,服务器将负责池化,否则如果是简单的 Java 客户端,则使用 Apache DBCP(如果用于数据库)或使用 Apache Commons Pooling API 见这里:Apache Commons

【讨论】:

【参考方案4】:

不要自己写。有很多库可以为您执行此操作,它们是开源且易于使用的,并且会解决您在尝试自己制作时遇到的所有问题。

这是一个使用 Apache 的 Commons DBCP 和 Commons Pool 的简单示例:

首先设置一个DataSource。

javax.sql.DataSource source = new org.apache.commons.dbcp.BasicDataSource();
source.setDriverClassName("com.mysql.jdbc.Driver");
source.setUsername("username");
source.setPassword("password");
source.setUrl("jdbc:mysql://localhost:3306/myDatabase");

一旦有了数据源,就很容易从池中获取连接。

java.sql.Connection connection = source.getConnection();

关闭连接会将其返回到池中。

connection.close();

【讨论】:

+1。但是,一个更正 - setDriverClassName() 和其他方法在 javax.sql.DataSource[java 1.6] 中不可用。类型应该是 BasicDataSource 。即:BasicDataSource source = new BasicDataSource(); 了解更多详情:svn.apache.org/viewvc/commons/proper/dbcp/trunk/doc/… 不要自己写,使用现有的“不支持、取消支持、历史”库,什么也学不到。我不同意。为什么新开发者不应该自己写,至少应该支持他们自己实现,以便他们可以学习。为什么不? “编写你自己的,并使用编写良好的单元测试和文档编写”【参考方案5】:

滚动您自己的 connpool 的一个参数是要避免的配置和其他 jar。我同意您需要启用 3rd 方接口,以便您可以在成熟的 connpool 中进行交换,但是拥有自己的微型解决方案可以占有一席之地。带有同步块的自清洁 Vector 和带有 close() 将 conn 标记为可用的 conn 包装器非常适用于 servlet 应用程序。

【讨论】:

【参考方案6】:

只需使用信号量。理想情况下,您应该使用CP3ODBCP 作为连接池。现在您可以根据信号量限制您的连接。

每次您执行Get 时,您都会从 Semaphore 中获取并在每次 Release 时释放它。更多信号量是线程安全的。

【讨论】:

【参考方案7】:

我希望这个源代码有帮助 http://jagadeeshmanne.blogspot.com/2014/03/connection-pool-in-java-jdbc.html

Configuration.java

package com.jmanne.utils;
 
public class Configuration 
  
 public String DB_USER_NAME ;
  
 public String DB_PASSWORD ;
  
 public String DB_URL;
  
 public String DB_DRIVER;
  
 public Integer DB_MAX_CONNECTIONS;
  
 public Configuration()
  init();
 
  
 private static Configuration configuration = new Configuration();
  
 public static Configuration getInstance() 
  return configuration;
 
  
 private void init()
  DB_USER_NAME = "root"
  DB_PASSWORD = "root"
  DB_URL = "jdbc:mysql://localhost:3306/jmanne"
  DB_DRIVER = "com.mysql.jdbc.Driver"
  DB_MAX_CONNECTIONS = 5
      

JdbcConnectionPool.java

package com.jmanne.db;
 
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
 
import com.jmanne.utils.Configuration;
import com.mysql.jdbc.Connection;
 
public class JdbcConnectionPool 
  
 List<connection> availableConnections = new ArrayList<connection>();
 
 public JdbcConnectionPool()
 
  initializeConnectionPool();
 
 
 private void initializeConnectionPool()
 
  while(!checkIfConnectionPoolIsFull())
  
   availableConnections.add(createNewConnectionForPool());
  
 
 
 private synchronized boolean checkIfConnectionPoolIsFull()
 
  final int MAX_POOL_SIZE = Configuration.getInstance().DB_MAX_CONNECTIONS;
 
  if(availableConnections.size() < MAX_POOL_SIZE)
  
   return false;
  
 
  return true;
 
 
 //Creating a connection
 private Connection createNewConnectionForPool()
 
  Configuration config = Configuration.getInstance();
  try 
   Class.forName(config.DB_DRIVER);
   Connection connection = (Connection) DriverManager.getConnection(
     config.DB_URL, config.DB_USER_NAME, config.DB_PASSWORD);
   return connection;
   catch (ClassNotFoundException e) 
   e.printStackTrace();
   catch (SQLException e) 
   e.printStackTrace();
  
  return null;
   
 
 
 public synchronized Connection getConnectionFromPool()
 
  Connection connection = null;
  if(availableConnections.size() > 0)
  
   connection = (Connection) availableConnections.get(0);
   availableConnections.remove(0);
  
  return connection;
 
 
 public synchronized void returnConnectionToPool(Connection connection)
 
  availableConnections.add(connection);
 

DataSource.java

package com.jmanne.db;
 
import java.sql.SQLException;
 
import com.mysql.jdbc.Connection;
 
public class DataSource 
  
 static JdbcConnectionPool pool = new JdbcConnectionPool();
  
 public static Connection getConnection() throws ClassNotFoundException, SQLException
  Connection connection = pool.getConnectionFromPool();
  return connection;
 
  
 public static void returnConnection(Connection connection) 
  pool.returnConnectionToPool(connection);
 

【讨论】:

db驱动是什么意思? 您能否举个例子来说明您将如何使用此代码? 抱歉耽搁了。 db driver 表示驱动程序类名。需要将该变量名称更改为 driverClass。您可以在服务类中使用 DataSource.getConnection()。它将从池中返回连接对象【参考方案8】:

我有一个相同的解决方案来创建一个连接池实用程序,它可以帮助您创建一个默认大小为 10 的池。

@组件 公共类连接池 private static final Logger logger = LoggerFactory.getLogger(ConnectionPool.class); 私有静态最终 int MAX_POOL_SIZE_LIMIT = 10; 私有 BlockingQueue activeConnectinoQueue = new LinkedBlockingQueue(); 私有阻塞队列 usedConnectinoList = new LinkedBlockingQueue(); 私有 int initialPoolSize = 5;

@Autowired
@Qualifier("dataSource")
private DataSource dataSource;

public void initConnectionPool() 
    logger.info("ConnectionPool initialization started.");
    if(activeConnectinoQueue.isEmpty() && usedConnectinoList.isEmpty()) 
        for (int i=0; i<initialPoolSize; i++) 
            createConnections();
        
    
    logger.info("ConnectionPool initialization completed. ConnectionPool size : ", activeConnectinoQueue.size());


private void createConnections() 
    try 
        Connection connection = dataSource.getConnection();
        activeConnectinoQueue.add(connection);
    catch (SQLException e) 
        logger.error("Error in getting connection from pool : ", e);
    


public Connection getConnection() 
    if(activeConnectinoQueue.isEmpty()) 
        initConnectionPool();
    
    Connection connection =  activeConnectinoQueue.remove();

    try 
        if(connection.isClosed()) 
            connection = dataSource.getConnection();
        
    catch (SQLException e) 
        logger.error("Error while getting connection from pool : ", e);
    

    usedConnectinoList.add(connection);
    return connection;



public void releaseConnection(Connection connection) 
    if(connection != null) 
        usedConnectinoList.remove(connection);
        activeConnectinoQueue.add(connection);
    


public void setInitialPoolSize(int initialPoolSize) 
    if(!(initialPoolSize < 0 || initialPoolSize > MAX_POOL_SIZE_LIMIT)) 
        this.initialPoolSize = initialPoolSize;
    


public int getInitialPoolSize() 
    return initialPoolSize;


public int getConnectionPoolSize() 
    return activeConnectinoQueue.size() + usedConnectinoList.size();


public void setDataSource(AbstractDataSource dataSource) 
    this.dataSource = dataSource;


public void closeConnectionPool() 

    logger.info("Closing connectionPool started.");
    close(usedConnectinoList);
    close(activeConnectinoQueue);
    logger.info("ConnectionPool Closed.");


private void close(BlockingQueue<Connection> connectinosQueue) 
    for (int i=0; i<connectinosQueue.size(); i++) 
        Connection connection = connectinosQueue.remove();
        if(connection != null) 
            try 
                connection.close();
             catch (SQLException e) 
                logger.error("Error in initializing connection pool : ", e);
            
        
    

现在为了安全,我们需要附加一个工厂对象..

public enum ConnectionFactory 
CONNECTION;

private ConnectionPool connectionPool;
public void setConnectionPool(ConnectionPool connectionPool) 
    this.connectionPool = connectionPool;


public Connection getConnection() 
    return connectionPool.getConnection();


public void closeConnection() 
    connectionPool.closeConnectionPool();


public void releaseConnection(Connection connection) 
    connectionPool.releaseConnection(connection);


public int getConnectionPoolSize() 
    return connectionPool.getConnectionPoolSize();


@Component
public static class ConnectionBuilder 
    @Autowired
    private ConnectionPool connectionPool;

    public void setConnectionPool(ConnectionPool connectionPool) 
        this.connectionPool = connectionPool;
    
    @PostConstruct
    public void postConstruct() 
        for (ConnectionFactory cfactory : EnumSet.allOf(ConnectionFactory.class)) 
            cfactory.setConnectionPool(connectionPool);
        
    

【讨论】:

【参考方案9】:

Java 连接池? 有3种方式来创建JDBC Connection Pooling 很简单...

    Apache Commons DBCP

    public class DBCPDataSource 
    
    private static BasicDataSource ds = new BasicDataSource();
    
    static 
        ds.setUrl("jdbc:h2:mem:test");
        ds.setUsername("user");
        ds.setPassword("password");
        ds.setMinIdle(5);
        ds.setMaxIdle(10);
        ds.setMaxOpenPreparedStatements(100);
    
    
    public static Connection getConnection() throws SQLException 
        return ds.getConnection();
    
    
    private DBCPDataSource() 
    
    

    现在可以连接了

    Connection con = DBCPDataSource.getConnection();
    

    HikariCP

    public class HikariCPDataSource 
    
    private static HikariConfig config = new HikariConfig();
    private static HikariDataSource ds;
    
    static 
        config.setJdbcUrl("jdbc:h2:mem:test");
        config.setUsername("user");
        config.setPassword("password");
        config.addDataSourceProperty("cachePrepStmts", "true");
        config.addDataSourceProperty("prepStmtCacheSize", "250");
        config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
        ds = new HikariDataSource(config);
    
    
    public static Connection getConnection() throws SQLException 
        return ds.getConnection();
    
    
    private HikariCPDataSource()
    
    

现在可以连接了

Connection con = HikariCPDataSource.getConnection();

    C3PO

     public class C3poDataSource 
    
    private static ComboPooledDataSource cpds = new ComboPooledDataSource();
    
    static 
        try 
            cpds.setDriverClass("org.h2.Driver");
            cpds.setJdbcUrl("jdbc:h2:mem:test");
            cpds.setUser("user");
            cpds.setPassword("password");
         catch (PropertyVetoException e) 
            // handle the exception
        
    
    
    public static Connection getConnection() throws SQLException 
        return cpds.getConnection();
    
    
    private C3poDataSource()
    
    

现在可以连接了

Connection con = C3poDataSource.getConnection();

【讨论】:

【参考方案10】:

我有一些 Java 模型代码,它具有多线程连接池。

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

【讨论】:

以上是关于需要代码在java中创建连接池的主要内容,如果未能解决你的问题,请参考以下文章

Java中的连接池和线程池设置

在 GlassFish v4.1.1 中创建 jdbc 连接池 [重复]

Springboot默认数据库连接池及常用属性

17 | Executor组件:Tomcat如何扩展Java线程池?

设计模式代理模式实现连接池

如何使用 context.bind 绑定 DataSource。连接池等