需要代码在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】:只需使用信号量。理想情况下,您应该使用CP3O
或DBCP
作为连接池。现在您可以根据信号量限制您的连接。
每次您执行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中创建连接池的主要内容,如果未能解决你的问题,请参考以下文章
在 GlassFish v4.1.1 中创建 jdbc 连接池 [重复]