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

时间:2010-05-13 11:02:01

标签: java connection connection-pooling

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

更新1:

我想用Simple 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();
 }

}

10 个答案:

答案 0 :(得分:46)

  

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

不确定问题是什么,但不创建另一个连接池,使用现有的解决方案,如C3P0Apache DBCPProxoolBoneCP(新的该领域的球员)。我会用C3P0。

  

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

因为如果从池中借用了连接但尚未返回,则它不在池中,也不能分配给池的另一个客户端(资源将从池中删除,直到它们被返回)。 / p>

  

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

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

答案 1 :(得分:13)

不要自己写。有很多图书馆员会为你做这个开源且易于使用的图书馆员,并且会解决你自己尝试制作的所有问题。

这是一个使用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");

一旦拥有了DataSource,就很容易从池中获得连接。

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

关闭连接会将它返回给你。

connection.close();

答案 2 :(得分:11)

我希望此源代码有所帮助 http://jagadeeshmanne.blogspot.in/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);
 }
}

答案 3 :(得分:6)

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

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

答案 4 :(得分:4)

使用其中一个,例如Apache DBCP

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

答案 5 :(得分:2)

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

答案 6 :(得分:2)

滚动自己的connpool的一个论点是配置和避免的其他jar。我同意您需要启用第三方接口,以便您可以交换成熟的连接,但拥有自己的小解决方案可以取而代之。自我清理带有synchronized块的矢量和带有close()标记conn的conn包装器可用于servlet应用程序。

答案 7 :(得分:0)

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

@Component 公共类ConnectionPool {     私有静态最终Logger logger = LoggerFactory.getLogger(ConnectionPool.class);     私有静态最终整数MAX_POOL_SIZE_LIMIT = 10;     私人BlockingQueue activeConnectinoQueue =新的LinkedBlockingQueue <>();     专用BlockingQueue usedConnectinoList = new LinkedBlockingQueue <>();     private 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);
        }
    }
}

}

答案 8 :(得分:0)

Java连接池?
创建JDBC连接池的三种方法非常简单...

  1. 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();
    
  2. 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();
  1. 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();

答案 9 :(得分:0)

我在Java中有一些模型代码,该模型代码具有带多线程的连接池。

set.seed(25)

xx <- data.frame(
  year = 2015,
  values = iris$Sepal.Length,
  score = sample(1:8, nrow(iris), replace = TRUE))
brks <- seq(0, ceiling(max(xx$values)), 0.5)