[Java项目实战系列]从0实现数据库连接池

本文给大家介绍为何需要数据库连接池,以及从0实现数据库连接池,代码行数不足1000行,非常易懂。
全部代码已开源:

为什么需要连接池

传统数据库连接生命周期:

  1. 使用驱动打开数据库连接
  2. 打开TCP socket用于后续读写数据
  3. 读写数据
  4. 关闭连接
  5. 关闭socket

可以看出数据库连接创建是一个非常昂贵的操作,我们应该尽可能避免频繁创建连接。传统的数据库访问方式,每次操作数据库都需要打开、关闭物理连接,非常耗费系统资源,性能差。而且数据库支持的连接数是有限的,创建大量的连接会导致数据库僵死。

解决方案:使用连接池,系统初始化后会创建容器,会申请一些连接对象,当需要访问数据库时,从容器中取连接对象直接使用,数据库操作结束后归还给容器。优点是节约资源,提高访问数据库的性能。

下图是使用连接池和不使用的对比:

一次SQL执行的过程:


业界连接池及对比

业界常见的连接池实现有:

  • DBCP
  • C3P0。2015年后已停止维护。
  • Druid
  • HikariCP
  • Tomcat的内置连接池

性能比较:


如何实现一个连接池

技术方案

核心要点:

  • 实现连接重用。连接使用后并不直接释放,而是归还到连接池,方便下一个请求使用。

核心步骤:

  • 初始化连接池,提前创建一定数量的空闲连接
  • 调用getConnection方法获取连接
    • 如果连接池中有空闲的连接,直接取空闲连接返回
    • 如果无,则判断当前连接池中的连接数是否超过最大阈值,如果是,等待,通过wait/notifyAll来实现
    • 如果未超过最大阈值,创建新连接,存入连接池
  • 调用returnConnection释放连接
    • 判断当前连接是否可用
    • 将连接置位空闲。

代码结构

类图:

核心类说明:

  • ILifeCycle接口定义数据源生命周期
  • IPooledConnection接口扩展自Connection,但是额外定义了为了实现池化功能新增的几个方法
  • PooledConnection是IPooledConnection接口的实现类,封装Connection,实现池化功能,可以理解为一个代理,主要是校验连接状态,将请求调用直接代理到实际的Connection
  • IPooledDataSource接口扩展自DataSource,但是额外定义了为了实现池化功能新增的几个方法
  • AbstractDataSource:数据源默认实现抽象类
  • DefaultDataSource:本次实现的池化数据源,负责连接的获取和回收,包含一个List<IPooledConnection>类型的成员属性,用来维护连接
  • DataSourceConfig和PooledDataSourceConfig定义了数据源基础配置和为了实现池化功能新增的配置
  • ConnPoolException:自定义异常
  • DriverUtil:驱动加载工具类

代码包结构:

测试

测试代码在类PooledDataSourceTest里。比如第一个测试方法,简单的先初始化,然后进行获取连接、释放连接的操作:
五月 18, 2022 8:14:14 上午 com.summer.dsconnpool.DefaultDataSource createConnection
信息: 创建新连接.....
五月 18, 2022 8:14:15 上午 com.summer.dsconnpool.DefaultDataSource getConnection
信息: getConnection begin....
五月 18, 2022 8:14:15 上午 com.summer.dsconnpool.DefaultDataSource logConnPoolDigest
信息: pooledConnectionList status:[1,busy status:[false,]]
五月 18, 2022 8:14:15 上午 com.summer.dsconnpool.DefaultDataSource getFreeConnectionFromPool
信息: 从连接池中获取连接
db_summer_1
五月 18, 2022 8:14:15 上午 com.summer.dsconnpool.DefaultDataSource getConnection
信息: getConnection begin....
五月 18, 2022 8:14:15 上午 com.summer.dsconnpool.DefaultDataSource logConnPoolDigest
信息: pooledConnectionList status:[1,busy status:[true,]]
五月 18, 2022 8:14:15 上午 com.summer.dsconnpool.DefaultDataSource getConnection
信息: 开始扩容连接池大小...
五月 18, 2022 8:14:15 上午 com.summer.dsconnpool.DefaultDataSource createConnection
信息: 创建新连接.....
五月 18, 2022 8:14:15 上午 com.summer.dsconnpool.DefaultDataSource getConnection
信息: 扩容完成...
五月 18, 2022 8:14:15 上午 com.summer.dsconnpool.DefaultDataSource logConnPoolDigest
db_summer_1
信息: pooledConnectionList status:[2,busy status:[true,true,]]
五月 18, 2022 8:14:15 上午 com.summer.dsconnpool.DefaultDataSource checkValid
信息: 开始校验连接
五月 18, 2022 8:14:15 上午 com.summer.dsconnpool.DefaultDataSource logConnPoolDigest
信息: pooledConnectionList status:[2,busy status:[false,true,]]

注意运行本次测试需要依赖本机安装mysql数据库。安装完毕后创建样例数据库。这里测试类里的相关配置可以根据需要进行修改:

dataSourceConfig.setDriverClass("com.mysql.jdbc.Driver");
dataSourceConfig.setJdbcUrl("jdbc:mysql://localhost:3306/db_summer_1?useUnicode=true&characterEncoding=utf-8");
dataSourceConfig.setUser("root");
dataSourceConfig.setPassword("summer");

还在等什么!赶紧下载代码学习把~



#面试##内推##面经##笔试题目##Java##项目#
全部评论

相关推荐

理想汽车前瞻硬件研发面经分享面试背景bg双非一本&nbsp;有两段大厂实习经历干的基本是测试+研发一面技术面(1.5h)全程无八股,聚焦项目细节深挖,节奏紧凑但交流顺畅。1.&nbsp;自我介绍(重点突出半导体+电子技术双背景、竞赛获奖及核心项目经历);2.&nbsp;实习工艺优化的核心难点是什么?测试方案3.项目改进点4.&nbsp;本科期间参与的项目和竞赛中,你觉得自己收获最大的能力是什么?5.&nbsp;项目中遇到过哪些实验数据与预期不符的情况?怎么解决的?6.半导体器件可靠性测试中&nbsp;是如何进行故障定位和参数优化的7.&nbsp;为什么选择自主搭建硬件平台而非用现成开发板?8.场景题输出调控报告9.手撕代码10.为什么要干硬件而不是嵌入式软件反问环节1.&nbsp;若入职,会具体负责哪类产品的研发2.&nbsp;工作中是否有机会深度参与核心参数优化、故障归因这类一线研发工作?压力强度如何?3.团队在器件选型、原理图设计方面有哪些规范或经验沉淀?涵盖产品需求分析、可行性报告撰写、硬件系统方案设计、EMC认证、功能安全设计、器件选型、原理图设计、工艺优化及单板调试,有专门团队负责,与我的技能匹配度很高。后续流程需等待HR面安排。二面HR面(40min)1.&nbsp;自我介绍(突出协作能力和项目成果);2.&nbsp;分享一下实习时,最具挑战性的任务是什么?怎么完成的?3.&nbsp;未来3-5年的职业规划是什么?希望在硬件领域往哪个细分方向深耕?4.并没有那么匹配的研发经历如何胜任工作5.&nbsp;竞赛的心路历程6.&nbsp;你是如何在项目中提升团队凝聚力的?举一个具体例子。7.&nbsp;到岗日期及实习时间反问环节1.公司针对实习生有哪些职业发展路径?是否有技术晋升或跨项目学习的机会?2.公司规模及构成已offer
查看20道真题和解析
点赞 评论 收藏
分享
2025-11-28 01:10
门头沟学院 Java
点赞 评论 收藏
分享
评论
6
9
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务