A Simple Guide to Connection Pooling in Java
作者 - Baeldung
About Author
一个简单的实现
为了更好地理解连接池的底层逻辑,让我们
创建一个简单的实现。
让我们从松耦合设计开始,仅基于一个
单界面:
public interface ConnectionPool {
Connection getConnection();
boolean releaseConnection(Connection connection);
String getUrl();
String getUser();
String getPassword();
}
ConnectionPool 接口定义了一个基本的公共 API
连接池。
现在,让我们创建一个实现,它提供了一些基本的
功能,包括获取和释放池连接:
public class BasicConnectionPool
implements ConnectionPool {
private String url;
private String user;
private String password;
private List<Connection> connectionPool;
private List<Connection> usedConnections = new ArrayList<>();
private static int INITIAL_POOL_SIZE = 10;
public static BasicConnectionPool create(
String url, String user,
String password) throws SQLException {
List<Connection> pool = new ArrayList<>(INITIAL_POOL_SIZE);
for (int i = 0; i < INITIAL_POOL_SIZE; i++) {
pool.add(createConnection(url, user, password));
}
return new BasicConnectionPool(url, user, password, pool);
}
// standard constructors
@Override
public Connection getConnection() {
Connection connection = connectionPool
.remove(connectionPool.size() - 1);
usedConnections.add(connection);
return connection;
}
@Override
public boolean releaseConnection(Connection connection) {
connectionPool.add(connection);
return usedConnections.remove(connection);
}
private static Connection createConnection(
String url, String user, String password)
throws SQLException {
return DriverManager.getConnection(url, user, password);
}
public int getSize() {
return connectionPool.size() + usedConnections.size();
}
// standard getters
}
连接池是一种众所周知的数据访问模式,其主要
目的是减少执行数据库所涉及的开销
连接和读/写数据库操作。
简而言之,连接池在最基本的层面上是一个
数据库连接缓存实现,可配置为
满足特定要求。
在本教程中,我们将快速总结一些流行的
连接池框架,我们将学习如何实现
划伤我们自己的连接池。
为什么要使用连接池?
当然,这个问题是修辞性的。
如果我们分析典型数据库中涉及的步骤顺序
连接生命周期,我们会明白为什么:
使用数据库驱动程序打开到数据库的连接
用于读取/写入数据的 TCP 套接字
socket 关闭连接 关闭socket 很明显
数据库连接是相当昂贵的操作,并且作为
这样,应该在每个可能的用例中减少到最低限度(在
边缘情况,只是避免)。
这就是连接池实现发挥作用的地方。
只需简单地实现一个数据库连接容器,它
允许我们重用一些现有的连接,我们可以
有效节省大量昂贵的执行成本
数据库旅行,从而提高了我们的整体性能
数据库驱动的应用程序。
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(){ }
}
在这种情况下,我们使用了一个带有静态块的包装类来轻松地
配置 DBCP 的属性。
以下是使用 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(){}
}
同样,以下是如何与
HikariCPDataSource 类:
Connection con = HikariCPDataSource.getConnection();