什么是连接池?如何确认连接池的大小?

对于我们编写的几乎每个网络或移动应用程序来说,其底层的关键组件之一就是数据库。对于编写使用数据库且高性能且资源高效的应用程序,必须处理一项关键资源,但与 CPU、内存等不同,它通常不是很明显。该资源是数据库连接。

什么是数据库连接?

使用MySQL作为DB的数据库连接

数据库连接是由数据库驱动程序创建的对象,数据库驱动程序是一个软件,用于管理与数据库通信的细节,并使我们的应用程序代码能够轻松地使用数据库。例如,MySQL连接可以通过com.mysql.jdbc.Driver驱动程序创建。连接维护许多东西,其中包括用于数据交换的套接字 (套接字是两台机器之间连接的松散逻辑表示)以及与数据库的会话,与典型的 Web 会话非常相似。

需要连接池

连接管理不善的陷阱

未正确关闭数据库连接是难以检测的错误来源。最常见的错误是:

  1. 'Too many connections'错误,数据库不接受客户端连接进行查询处理。
  2. 某种形式的内存溢出(例如:'Heap OutOfMemoryError'):由于打开的连接在内存中累积而发生。

即使 Web 应用程序中服务请求的单个位置没有正确关闭连接,随着时间的推移,也可能会因上述错误而导致应用程序崩溃。

使用连接池通常可以减少或消除此类错误。

引入连接池的效果

考虑以下简单程序,它在数据库上运行 1000 个查询:

ini 复制代码
for i = 1 to 1000
    connection = Driver.getConnection()
    result = connection.executeQuery(query)
    connection.close()

上面代码中我们创建和关闭连接的次数随着执行的查询数量线性增加。

该程序可以通过使用一个非常简单的连接池来高度优化,连接池只是活动数据库连接的缓存。​​​​​​​

ini 复制代码
Pool = CreateConnectionPool(size = 2)
for i = 1 to 1000
    connection = Pool.getConnection()
    result = executeQuery(query, connection)
    Pool.returnConnection(connection)

连接池的简化表示

在这里,创建连接被从池中获取连接所取代,而关闭连接则被返回到池中所取代,后者速度更快。

无池(~34 秒)

java 复制代码
// Query Execution without pool ---> ~34 sec
public static void main(String[] args) throws SQLException {
    long start = System.currentTimeMillis();
    for(int i = 0 ;i < 1000; i++){
        // 1. Application will load the suitable MySQL Driver, eg: com.mysql.jdbc.Driver, com.mysql.cj.jdbc.Driver
        // 2. Driver will connect to the MySQL DB using the provided URL for the DB and credentials
        // 3. Driver will return a connection object corresponding to created DB connection
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/my_db", "root", "");
        
        connection.createStatement().execute("select count(*) from places");
        
        // release connection
        connection.close();
    }
    System.out.println(System.currentTimeMillis() - start);

带池(非常幼稚的实现)(~16 秒)

ini 复制代码
//Query execution using a very simplistic Connection Pool ---> ~16 sec
public static void main(String[] args) throws SQLException {
    long start = System.currentTimeMillis();

    // create pool
    List<Connection> pool = new ArrayList<>();
    for(int i = 0; i < 10;i++){
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/my_db", "root", "");
        pool.add(connection);
    }

    Random r = new Random();
    for(int i = 0 ;i < 1000; i++){
        // get connection
        int randomIdx = r.nextInt(10);
        Connection connection = pool.get(randomIdx);
        pool.remove(randomIdx);

        connection.createStatement().execute("select count(*) from places");
        
        // release connection
        pool.add(randomIdx, connection);

    }
    System.out.println(System.currentTimeMillis() - start);
}

连接池虽然以非常简单的方式实现,但却导致程序执行时间减少了50% 以上(执行时间从 34 秒至 16 秒)。

复杂的连接池库,例如HikariCP、C3P0等,可以带来巨大的性能提升并为您的应用程序带来资源效率。

如何确定连接池的大小

假设您有一个 Web 应用程序,其中处理每个请求都需要对数据库记录执行操作,并且您在阅读本文后决定使用连接池。

如果您的 Web 应用程序要处理 100 个并发请求的负载,那么连接池的大小应该是多少?100,对吗(每个请求 1 个)?

答案是,这取决于几个因素,而且大多数情况下,必须通过实验得出适当的值。需要考虑的一些因素如下:

  1. 您的网络应用程序处理的并发请求数
  2. 平均查询执行时间
  3. DB资源(CPU核心、磁盘速度)

但它通常比人们通常想象的要低。例如,对于上例中的 100 个并发请求,好的池大小大多不会大于 10。最后,这里有一个图可以直观地考虑大小调整:

作者:Ajay Joshi

更多技术干货请关注公号【云原生数据库

squids.cn,云数据库RDS,迁移工具DBMotion,云备份DBTwin等数据库生态工具。

irds.cn,多数据库管理平台(私有云)。

相关推荐
市场部需要一个软件开发岗位10 分钟前
JAVA开发常见安全问题:纵向越权
java·数据库·安全
海奥华212 分钟前
mysql索引
数据库·mysql
2601_949593651 小时前
深入解析CANN-acl应用层接口:构建高效的AI应用开发框架
数据库·人工智能
javachen__1 小时前
mysql新老项目版本选择
数据库·mysql
Dxy12393102161 小时前
MySQL如何高效查询表数据量:从基础到进阶的优化指南
数据库·mysql
Dying.Light1 小时前
MySQL相关问题
数据库·mysql
蜡笔小炘2 小时前
LVS -- 利用防火墙标签(FireWall Mark)解决轮询错误
服务器·数据库·lvs
韩立学长2 小时前
基于Springboot泉州旅游攻略平台d5h5zz02(程序、源码、数据库、调试部署方案及开发环境)系统界面展示及获取方式置于文档末尾,可供参考。
数据库·spring boot·旅游
Re.不晚3 小时前
MySQL进阶之战——索引、事务与锁、高可用架构的三重奏
数据库·mysql·架构
老邓计算机毕设3 小时前
SSM智慧社区信息化服务平台4v5hv(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面
数据库·ssm 框架·智慧社区、·信息化平台