需要代码在java中创建连接池吗? 我们如何确保连接池不返回已在使用的同一对象? 如果客户端从连接池中取出连接后关闭连接会怎么样?
我想用Simple Java术语创建它,并想看看它在多线程环境中的工作原理。我的意思是哪些方法会同步,哪些方法不同步。这门课还会成为公共课吗?如果是,则任何人都可以访问此类并重新初始化连接池吗?
我有一些代码如下。但我不知道如何“关闭来自池的连接将其返回到池中,它不会在物理上关闭连接。” 此外,我没有理解这个“因为如果连接已从池中借用但尚未返回,则它不是”可用“,并且不能重新分配给池中的另一个客户端。”
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();
}
}
答案 0 :(得分:46)
需要代码在java中创建连接池吗?
不确定问题是什么,但不创建另一个连接池,使用现有的解决方案,如C3P0,Apache DBCP,Proxool或BoneCP(新的该领域的球员)。我会用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)
只需使用信号量。理想情况下,您应该使用CP3O
或DBCP
作为连接池。现在,您可以根据信号量限制连接。
每次执行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连接池的三种方法非常简单...
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();
答案 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)