【Spring Boot 应用开发】-04-01 自动配置-数据源-连接池

news2025/1/14 10:48:28

资源关闭

还记得上一节中的这段代码么?

try {
    if (resultSet != null) resultSet.close();
    if (preparedStatement != null) preparedStatement.close();
    if (connection != null) connection.close();
} catch (SQLException e) {
    e.printStackTrace();
}

这是我们在查询完毕之后,关闭和释放资源。我们都知道数据库可接受的链接是有限的,如果不进行关闭,那么可用连接就会被耗尽,这样新的访问就无法被处理了。更全面的说明如下:

为什么必须关闭数据库连接

  1. 资源管理

    • 解释:数据库连接是有限的资源。每个连接都需要占用数据库服务器的内存、线程和其他系统资源。如果不关闭连接,这些资源将一直被占用,可能导致资源耗尽。
    • 后果:当数据库连接耗尽时,新的连接请求将被拒绝,应用程序将无法继续正常工作。
  2. 性能优化

    • 解释:频繁地建立和关闭连接会导致性能下降。每次建立连接都需要进行上述的多个步骤,耗时较长。
    • 后果:这会降低应用程序的响应速度和吞吐量。
  3. 避免资源泄漏

    • 解释:如果连接没有被正确关闭,它们会一直保持打开状态,导致资源泄漏。
    • 后果:长时间运行的应用程序可能会因为资源泄漏而变得不稳定,甚至崩溃。
  4. 事务管理

    • 解释:未关闭的连接可能会导致事务管理问题。如果连接没有正确关闭,事务可能不会被正确提交或回滚。
    • 后果:这可能导致数据不一致和其他事务相关的问题。
  5. 安全性

    • 解释:未关闭的连接可能会被恶意利用,导致安全风险。
    • 后果:攻击者可能利用未关闭的连接进行未经授权的操作,导致数据泄露或其他安全问题。

上面出现了多次“泄露”这个词,为什么用这个词呢?因为资源被耗尽这种现象类似于水装满了,从容器中意外流出的场景,就像下面这个图:
在这里插入图片描述

给个池子

怎么来解决这个问题呢?

解决任何问题都可以在中间加一层

数据库连接池

产生背景

在早期的数据库应用开发中,每次应用程序需要访问数据库时,都会创建一个新的数据库连接。这种做法存在以下几个问题:

  • 性能开销大:建立和关闭数据库连接是一个相对耗时的操作,频繁的连接操作会显著降低应用程序的性能。
  • 资源浪费:每次创建新的连接都会消耗系统资源,过多的连接会导致资源耗尽,影响系统的稳定性。
  • 并发控制困难:在高并发环境下,频繁创建和关闭连接会导致数据库服务器负载过高,难以有效控制并发访问。

为了解决这些问题,数据库连接池应运而生。连接池预先创建一定数量的数据库连接,并将这些连接保存在一个池中,应用程序需要访问数据库时,可以直接从连接池中获取已建立的连接,使用完毕后再将连接归还到池中,而不是关闭连接。这种方式大大提高了性能和资源利用率。

特性
  1. 连接复用:连接池中的连接可以被多个请求复用,减少了创建和关闭连接的开销。
  2. 性能优化:通过预先创建和管理连接,连接池能够显著提高数据库访问的性能。
  3. 资源管理:连接池能够有效管理数据库连接的生命周期,避免资源浪费。
  4. 并发控制:通过配置连接池的最大连接数等参数,可以有效控制并发访问的数量,防止数据库服务器过载。
  5. 简化开发:开发者无需手动管理数据库连接的生命周期,由连接池自动处理,降低了代码复杂度。
场景
  • Web应用:在Web应用中,数据库连接池可以显著提高响应速度和并发处理能力。
  • 分布式系统:在分布式系统中,连接池能够有效管理多个节点之间的数据库连接,提高系统的整体性能和稳定性。
  • 大数据处理:在大数据处理场景中,连接池能够有效管理大量的数据库连接,确保数据处理的高效性和稳定性。
常见的高性能数据库连接池框架
  1. HikariCP

    • 特点:HikariCP是一个高性能的JDBC连接池,设计目标是成为最快的JDBC连接池。
    • 优点:低延迟、高性能、易于配置。
    • 适用场景:适用于需要高性能和低延迟的应用场景。
  2. C3P0

    • 特点:C3P0是一个开源的JDBC连接池,支持JNDI绑定和JMX管理。
    • 优点:功能丰富、支持多种数据库。
    • 适用场景:适用于需要多种数据库支持和复杂配置的应用场景。
  3. Druid

    • 特点:Druid是一个阿里巴巴开源的数据库连接池,提供了强大的监控和扩展功能。
    • 优点:监控功能强大、支持多种数据库、易于扩展。
    • 适用场景:适用于需要监控和扩展功能的应用场景。
  4. Tomcat JDBC Pool

    • 特点:Tomcat JDBC Pool是Apache Tomcat自带的连接池,轻量级且易于集成。
    • 优点:轻量级、易于集成。
    • 适用场景:适用于轻量级应用和嵌入式应用。
代码示例

以下是一个使用HikariCP作为数据库连接池的Spring Boot配置示例:

# application.yaml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb
    username: root
    password: secret
    driver-class-name: com.mysql.cj.jdbc.Driver
    hikari:
      maximum-pool-size: 10 # 最大连接数
      minimum-idle: 5       # 最小空闲连接数
      idle-timeout: 30000   # 空闲连接超时时间(毫秒)
      connection-timeout: 20000 # 获取连接超时时间(毫秒)

Spring Boot 2.0之后,只要你依赖了spring-boot-starter-jdbc自动配置类,那么在启动之后,会默认使用连接池,且默认连接池就是hikari,即使不显示的配置hikari参数,那么也会使用默认的参数

Hikari数据库连接池的实现原理

1.核心组件
  • HikariDataSource:作为应用程序与 HikariCP 交互的主要接口,实现了 javax.sql.DataSource 接口。
  • PoolBase:负责管理连接池的基本功能,如创建新连接、维护连接状态等。
  • HikariPool:继承自 PoolBase,是连接池的核心实现类,负责连接的分配、回收以及健康检查。
  • ConnectionProxy:代理实际的 JDBC 连接对象,用于拦截和处理连接的操作,确保连接在使用完毕后能正确返回到池中。
2.初始化过程
  • 当创建 HikariDataSource 实例时,会根据配置参数初始化 HikariCP 的内部状态。
  • 调用 initializePool() 方法启动后台线程(如果启用了连接测试),并预填充一定数量的空闲连接到池中。
3. 获取连接
  • 应用程序调用 getConnection() 方法请求连接。
  • 如果池中有可用连接,则直接返回给调用者;否则,尝试创建新的物理连接或等待其他线程归还连接。
  • 使用完连接后,必须显式地关闭它,这实际上只是将连接归还给池而不是真正关闭。
4. 连接回收
  • 当连接被归还给池时,会先进行健康检查(可选)。
  • 如果连接仍然有效,则将其标记为可用;若无效则销毁该连接并在需要时补充新的连接。
5. 空闲连接清理
  • 定期扫描池中的空闲连接,并根据配置规则移除那些长时间未使用的连接以节省资源。

6.源码分析
// HikariDataSource.java
public class HikariDataSource implements DataSource {
    private final HikariPool pool;

    public HikariDataSource() {
        this.pool = new HikariPool(this);
    }

    @Override
    public Connection getConnection() throws SQLException {
        return pool.getConnection();
    }
}

// HikariPool.java (部分代码)
public class HikariPool extends PoolBase {
    private final ConcurrentBag<PoolEntry> connectionBag;
    
    // 获取连接的方法
    public Connection getConnection() throws SQLException {
        final long startTime = System.nanoTime();
        final TimeTracker tracker = new TimeTracker(startTime);
        
        try {
            // 尝试从池中获取连接
            PoolEntry entry = connectionBag.borrow(timeout, MILLISECONDS);
            
            if (entry == null) {
                throw new SQLException("Timeout after " + timeout + "ms waiting for connection.");
            }

            // 返回代理后的连接
            return entry.getConnection();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new SQLException("Interrupted while waiting for a connection.", e);
        }
    }
}

以上代码片段展示了 HikariCP 中如何通过 HikariDataSourceHikariPool 类来管理数据库连接的获取与释放。实际源码更为复杂,包含了更多细节处理逻辑,例如连接超时、异常处理等。这里不做过多阐述,有兴趣的朋友可以私聊共学。


7.获取连接的时序图
应用程序 HikariDataSource HikariPool ConcurrentBag 数据库 Connection getConnection() getConnection() borrow() 返回PoolEntry 返回代理后的Connection 创建新连接 返回新连接 添加新连接到池 返回PoolEntry 返回代理后的Connection alt [池中有可用连接] [池中无可用连接] 使用连接 close() 归还连接 返回PoolEntry到池中 应用程序 HikariDataSource HikariPool ConcurrentBag 数据库 Connection

为什么jdbc中不直接给池子?

那很多童鞋会问了,为啥JDBC不直接提供一个连接池呢?搞这么麻烦,我要一站式服务。其实这是有原因的。如下:

1. 灵活性和可扩展性

  • 不同需求:不同的应用程序对连接池的需求可能不同。一些应用程序可能需要高性能的连接池,而另一些可能需要更复杂的连接管理功能。内置连接池可能会限制这种灵活性。
  • 第三方库:通过将连接池功能分离到第三方库中,JDBC允许开发者根据具体需求选择合适的连接池实现。例如,HikariCP、C3P0、Druid等都是高性能的连接池库,开发者可以根据自己的需求选择最适合的库。

2. 标准与实现分离

  • 标准定义:JDBC作为标准API,主要定义了与数据库交互的基本接口和方法。连接池功能属于更高层次的实现细节,不适合直接包含在标准API中。
  • 实现多样性:通过将连接池功能分离,不同的数据库厂商和第三方开发者可以提供多种实现,满足不同场景的需求。这种多样性有助于推动技术的发展和创新。

3. 性能优化

  • 定制化:不同的应用场景可能需要不同的性能优化策略。内置连接池可能无法提供针对特定场景的最佳优化,而第三方库可以根据具体需求进行定制和优化。
  • 轻量级:JDBC作为基础API,保持轻量级有助于提高整体性能。内置连接池可能会增加不必要的开销,影响JDBC的性能表现。

4. 复杂性管理

  • 简化核心:JDBC的核心功能是提供数据库访问的基本接口和方法。如果将连接池功能内置,会增加JDBC的复杂性,使得API更加庞大和难以维护。
  • 模块化设计:通过模块化设计,JDBC保持了核心功能的简洁性,而将连接池等功能交由第三方库实现,使得整个生态系统更加灵活和高效。

5. 历史原因

  • 早期设计:JDBC的设计始于1997年,当时连接池技术尚未成熟。随着时间的推移,连接池技术得到了快速发展,形成了多种成熟的第三方库。
  • 社区贡献:连接池功能主要由社区贡献和维护,这种方式促进了技术的快速迭代和优化。

6. 兼容性

  • 跨平台:JDBC作为跨平台的标准API,内置连接池可能会导致兼容性问题。第三方库可以针对不同的平台和环境进行优化,确保更好的兼容性。
  • 版本管理:通过将连接池功能分离,可以独立管理连接池库的版本,避免与JDBC版本之间的冲突和兼容性问题。

7. 安全性

  • 隔离性:将连接池功能分离可以提高安全性,避免核心API中引入不必要的复杂性和潜在的安全漏洞。
  • 模块化安全:第三方库可以独立进行安全审计和更新,确保连接池功能的安全性。

JDBC不直接内置数据库连接池遵循的核心原则是:让你的模块遵循单一职责原则,这样可以让整个模块的安全性、扩展性等更好,要小而精,不要大而全。这也是我们设计模块可以借鉴的地方。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2276440.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AngularJs指令中出错:Error: $compile:nonassign Non-Assignable Expression

Expression {resumeId: item.resumeId} used with directive rwdsDelete is non-assignable! 在AngularJS中&#xff0c;$compile服务用于将指令编译成HTML。当你在模板中使用了一个表达式&#xff0c;但这个表达式不是一个左值&#xff08;即不能被赋值的表达式&#xff09;时…

Docker 的安装和基本使用[SpringBoot之Docker实战系列] - 第535篇

历史文章&#xff08;文章累计530&#xff09; 《国内最全的Spring Boot系列之一》 《国内最全的Spring Boot系列之二》 《国内最全的Spring Boot系列之三》 《国内最全的Spring Boot系列之四》 《国内最全的Spring Boot系列之五》 《国内最全的Spring Boot系列之六》 《…

聚铭网络当选中关村华安关键信息基础设施安全保护联盟理事单位

近日&#xff0c;在北京隆重举行的中关村华安关键信息基础设施安全保护联盟&#xff08;以下简称“联盟”&#xff09;第一届第四次会员大会上&#xff0c;聚铭网络凭借其在网络安全领域的卓越贡献和创新实力&#xff0c;成功当选为联盟的理事单位。此次大会吸引了来自政府机关…

CES 2025|全面拥抱端侧AI,美格智能在CES发布系列创新成果

要点&#xff1a; ▶ 在AI机器人领域&#xff0c;以高算力AI模组助力发布“通天晓”人形机器人和2款全新微小型AI机器人 ▶ 在AI硬件领域&#xff0c;发布消费级AI智能体产品——AIMO&#xff0c;引领个人专属的大模型时代 ▶ 在5G通信领域&#xff0c;发布全新5GWiFi-7 CPE…

VScode 配置 C语言环境

遇到的问题集合 mingw官方下载网站&#xff08;https://sourceforge.net/projects/mingw-w64/files/&#xff09;更新之后&#xff0c;与网上大多数教程上写的界面不同了。 网上大多数教程让下载这个&#xff1a; 但是现在找不到这个文件。 写hello.c文件时&#xff0c;报错&…

013:深度学习之神经网络

本文为合集收录&#xff0c;欢迎查看合集/专栏链接进行全部合集的系统学习。 合集完整版请参考这里。 深度学习是机器学习中重要的一个学科分支&#xff0c;它的特点就在于需要构建多层且“深度”的神经网络。 人们在探索人工智能初期&#xff0c;就曾设想构建一个用数学方式…

STM32-Flash存储

目录 1.0 闪存模块组织 2.0 Flash基本结构 3.0 Flash解锁 4.0 指针访问存储器地址 5.0 程序存储器编程 6.0 选项字节 7.0 选项字节编程 8.0 选项字节擦除 9.0 电子签名 10.0 手册解读 定义&#xff1a; STM32F1系列的FLASH包含程序存储器、系统存储器和选项字节三个部…

工程水印相机结合图纸,真实现场时间地点,如何使用水印相机,超简单方法只教一次!

在工程管理领域&#xff0c;精准记录现场信息至关重要。水印相机拍照功能&#xff0c;为工程人员提供了强大的现场信息记录工具&#xff0c;助力工程管理和统计工程量&#xff0c;更可以将图片分享到电脑、分享给同事&#xff0c;协同工作。 一、打开图纸 打开手机版CAD快速看图…

Oracle 分区索引简介

目录 一. 什么是分区索引二. 分区索引的种类2.1 局部分区索引&#xff08;Local Partitioned Index&#xff09;2.2 全局分区索引&#xff08;Global Partitioned Index&#xff09; 三. 分区索引的创建四. 分区索引查看4.1 USER_IND_COLUMNS 表4.2 USER_INDEXES 表 五. 分区索…

JDK安装配置保姆级教程【图文详解】

目录 一. JDK介绍 二. JDK下载 三. JDK安装 四. 配置环境 五. 验证安装 一. JDK介绍 Java 环境分JDK 和JRE &#xff0c;JDK就是Java Development Ki&#xff0c;JDK是面向开发人员使用的SDK&#xff0c;它提供了Java的开发环境和运行环境。本文以Windows 11系统&#xff0c;JD…

浅谈云计算01 | 云计算服务的特点

在当今数字化时代&#xff0c;云计算作为一种强大的技术解决方案&#xff0c;正逐渐改变着企业和个人对信息技术的使用方式。本文将详细探讨云计算的五个主要特点&#xff0c;包括按需自助服务、广泛的网络接入、资源池化、快速弹性伸缩以及可计量服务。 一、按需自助服务 云…

【Git版本控制器--1】Git的基本操作--本地仓库

目录 初识git 本地仓库 认识工作区、暂存区、版本库 add操作与commit操作 master文件与commit id 修改文件 版本回退 撤销修改 删除文件 初识git Git 是一个分布式版本控制系统&#xff0c;主要用于跟踪文件的更改&#xff0c;特别是在软件开发中。 为什么要版本…

Unity使用Vuforia插件进行AR开发

零、最终效果 Unity使用Vuforia插件进行AR开发 一、资源准备 1、在Unity中添加Vuforia插件 &#xff08;1&#xff09;在UnityAssetStore中搜索Vuforia插件并添加到自己的资源中 网页地址&#xff1a;https://assetstore.unity.com/packages/templates/packs/vuforia-engine…

瑞芯微 RK 系列 RK3588 使用 ffmpeg-rockchip 实现 MPP 视频硬件编解码-代码版

前言 在上一篇文章中&#xff0c;我们讲解了如何使用 ffmpeg-rockchip 通过命令来实现 MPP 视频硬件编解码和 RGA 硬件图形加速&#xff0c;在这篇文章&#xff0c;我将讲解如何使用 ffmpeg-rockchip 用户空间库&#xff08;代码&#xff09;实现 MPP 硬件编解码。 本文不仅适…

Web前端界面开发

前沿&#xff1a;介绍自适应和响应式布局 自适应布局&#xff1a;-----针对页面1个像素的变换而变化 就是我们上一个练习的效果 我们的页面效果&#xff0c;随着我们的屏幕大小而发生适配的效果&#xff08;类似等比例&#xff09; 如&#xff1a;rem适配 和 vw/vh适配 …

OpenCV基础:视频的采集、读取与录制

从摄像头采集视频 相关接口 - VideoCapture VideoCapture 用于从视频文件、摄像头或其他视频流设备中读取视频帧。它可以捕捉来自多种源的视频。 主要参数&#xff1a; cv2.VideoCapture(source): source: 这是一个整数或字符串&#xff0c;表示视频的来源。 如果是整数&a…

C++内存泄露排查

内存泄漏是指程序动态分配的内存未能及时释放&#xff0c;导致系统内存逐渐耗尽&#xff0c;最终可能造成程序崩溃或性能下降。在C中&#xff0c;内存泄漏通常发生在使用new或malloc等分配内存的操作时&#xff0c;但没有正确地使用delete或free来释放这块内存。 在日常开发过程…

Golang 简要概述

文章目录 1. Golang 的学习方向2. Golang 的应用领域2.1 区块链的应用开发2.2 后台的服务应用2.3 云计算/云服务后台应用 1. Golang 的学习方向 Go 语言&#xff0c;我们可以简单的写成 Golang 2. Golang 的应用领域 2.1 区块链的应用开发 2.2 后台的服务应用 2.3 云计算/云服…

51c自动驾驶~合集46

我自己的原文哦~ https://blog.51cto.com/whaosoft/13050104 #世界模型会是L3自动驾驶的唯一解吗 三维空间占有率&#xff08;3D Occupancy&#xff09;预测的目的是预测三维空间中的每个体素是否被占有&#xff0c;如果被占有&#xff0c;则对应的体素将被标记。3D Semant…

从CentOS到龙蜥:企业级Linux迁移实践记录(龙蜥开局)

引言&#xff1a; 在我们之前的文章中&#xff0c;我们详细探讨了从CentOS迁移到龙蜥操作系统的基本过程和考虑因素。今天&#xff0c;我们将继续这个系列&#xff0c;重点关注龙蜥系统的实际应用——特别是常用软件的安装和配置。 龙蜥操作系统&#xff08;OpenAnolis&#…