「数据库、数据库连接池、数据源」这些概念你真的理解了吗?

news/2024/4/24 21:01:19/

前言

我学习的过程中,对于连接池和数据源分得不是很清楚,而且我发现有的人将数据库等同于数据源,或者将数据源等同于连接池,实际上这些说法并不准确。

在某次工作中,同事 A 说道,这个数据源不行,那么换一个数据源就可以了,结果我看他操作,原来是改写了配置中的数据库连接的 URL,当时我在想,这就是换数据源了?我以为说是把 Druid 这个数据源换掉。至于为什么会这么想,主要是因为有个 DruidDataSource

现在,搞清楚它们的区别不妨听我说说,欢迎大家在评论区说出你的看法!

数据库

一提到数据库,大家都会想到 MySQL、Oracle、PostgreSQL 这些。我们也习惯这样讲:我这个项目的数据库使用的是 MySQL,是吧。

实际上,严格来讲,这些是数据库管理系统(Database Management System,DBMS),它们是一种可以操作和管理数据库(Database)的软件。真正的数据库是指存储数据的仓库,这些数据都是持久化存储在计算机的硬盘上的。

比如 MySQL,我们在 MySQL 客户端使用 CREATE DATABASE db_demo; 命令,这样就创建了一个名为 db_demo 的数据库。

我们可以使用 SHOW VARIABLES LIKE '%datadir'; 命令查看数据库存放在哪个地方。

数据库连接池

那什么是数据库连接池呢?在说什么是连接池之前,我们先说说什么是连接(Connection、Connect)。

连接

在一开始学习 MySQL 的时候,我们通过 MySQL 的客户端来连接上 MySQL 的服务端:

mysql -u root -p 123456

当出现如下输出时,就说明我们成功连接上 MySQL 的服务端,接着就能输入各种 SQL 语句了:

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 81
Server version: 5.7.39 MySQL Community Server (GPL)Copyright (c) 2000, 2022, Oracle and/or its affiliates.Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.mysql>

以上的连接,只是连接到 MySQL 服务端,并没有指定连接到哪一个数据库,当然我们可以通过 USE 数据库名称 来切换到指定的数据库,后续的操作都是在该数据库上进行。

此处的连接,是一个动作,即 Connect。

我们在学习 JDBC 的时候,知道了想要通过 Java 去操作数据库,那么就需要借助 JDBC 来操作。

在这个过程中,我们首先需要加载数据库的驱动,然后建立 Java 程序与某个数据库的连接:

String driver = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/db_demo";
String username = "root";
String password = "123456";
// 加载驱动
Class.forName(driver);
// 获取该数据库连接(即帮我们创建了一个可以操作db_demo的连接对象)
Connection conn = DriverManager.getConnection(url, username, password);

获取完之后,我们就能通过连接获取相关的 Statement 对象(比如预编译的 PreparedStatement 对象),将我们的 SQL 语句丢给 Statement 对象,通过 Statement 对象执行操作。

操作完毕后就关闭了数据库连接。

conn.close();

这里的连接,是一个动作,也是一个对象,因为 Java 是面向对象的,抽象出了一个连接对象,这个连接对象包含了驱动信息、连接的 URL、DBMS 的用户名和密码,主要表明了此次连接到的是哪个数据库。

池化技术

现在,我们每进行一次相关的数据库操作,就需要经过打开/建立连接,执行相关操作,销毁/关闭连接这么一个过程。

对于一个简单的、对数据库的操作不是很频繁的应用来说,问题不大,不会有很明显的性能开销。

但是,对于一个经常操作数据库的应用来说,当有许多操作的请求过来时,多次的创建与销毁连接对象,是相当耗费资源的,比如网络带宽,内存,CPU 的运算等等。当然除了耗费资源,创建与销毁也会耗费时间。所以就有了数据库连接池的出现,这种是属于「池化技术」

池化技术有这样的特点,就是提前准备,然后进行复用。对于数据库连接池,就是提前准备好一定量的连接对象放在一个「池子」中,你可以想象水池,有一定量的水。当有需要的时候,就从这个池子中获取连接对象,然后进行数据库的操作,操作完了后,就把对象放回池子中。这就是所谓的「数据库连接池」

这里也就有种用空间换时间的感觉,通过准备一定量的连接对象,避免由调用者手动去打开和关闭连接,进而提高效率。

自己实现一个数据库连接池

选择你喜欢的一个地方新建一个类和一个配置文件,我将这两个东西放在了同一个目录下:

db.properties:

# 数据库相关配置
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/db_one_demo
username=root
password=123456
# 初始化的数据库连接池大小
initialPoolSize=5

ConnectionPool.java:

/*** @author god23bin* @description 简单的数据库连接池*/
public class ConnectionPool {private static String driver;private static String url;private static String username;private static String password;/*** 使用一个List来存放连接,将这个List作为连接池**/private static List<Connection> connectionPool;/*** 标记对应的连接是否被使用,是为 true,否为 false**/private static List<Boolean> usedConnections;/*** 连接池大小,即池子中连接的个数**/private static int initialPoolSize;// 读取配置文件只需要一次就够了,所以用static代码块static {//读取文件配置InputStream inputStream = null;Properties properties = new Properties();try {// 如果你的是 Spring Boot 应用,db.properties 放在 resource 目录下,则可以通过 ClassPathResource 来获取这个配置文件// inputStream = new ClassPathResource("db.properties").getInputStream();inputStream = ConnectionPool.class.getClassLoader().getResourceAsStream("db.properties");properties.load(inputStream);driver = properties.getProperty("driver");url = properties.getProperty("url");username = properties.getProperty("username");password = properties.getProperty("password");initialPoolSize = Integer.parseInt(properties.getProperty("initialPoolSize"));connectionPool = new ArrayList<>(initialPoolSize);usedConnections = new ArrayList<>(initialPoolSize);// 加载驱动Class.forName(driver);// 创建连接并将连接放到List集合中,标记为未被使用for (int i = 0; i < initialPoolSize; i++) {Connection connection = DriverManager.getConnection(url, username, password);connectionPool.add(connection);usedConnections.add(false);}} catch (IOException | SQLException | ClassNotFoundException e) {e.printStackTrace();}}/*** 获取连接* @return java.sql.Connection 返回连接对象**/public synchronized Connection getConnection() throws SQLException {// 判断是否有空闲的连接可用,有的话就标记为使用中,接着返回这个连接for (int i = 0; i < initialPoolSize; i++) {if (!usedConnections.get(i)) {usedConnections.set(i, true);return connectionPool.get(i);}}// 如果没有可用的连接,那么创建一个新的连接,把它加入到池中,并返回,简单处理,这里的创建并没有上限Connection connection = DriverManager.getConnection(url, username, password);connectionPool.add(connection);usedConnections.add(true);initialPoolSize++;return connection;}/*** 释放连接,将其标记为未使用* @param connection 连接**/public synchronized void releaseConnection(Connection connection) {int index = connectionPool.indexOf(connection);usedConnections.set(index, false);}
}

目前我知道的开源的数据库连接池有 DBCP、C3P0,还有阿里的 Druid。

数据源

数据源(Data Source),即数据的来源。在咱们开发的应用中,数据可以来源于网络,也可以来源于本地的文件,还可以来源于数据库。

简而言之,数据源指定了数据从哪里来。换句话说,数据源是指存储数据的位置。

在 Java 中,有一个 javax.sql.DataSource 接口,这个接口定义了一组获取数据库连接的方法。

  • Connection getConnection() throws SQLException
  • Connection getConnection(String username, String password) throws SQLException

以上,就是所谓的数据源。

数据源和连接池的关系

**有的人会把数据源等同于连接池,那到底是不是呢?**从概念上看,明显不是一个东西,数据源是数据来源,连接池则是连接的缓存池,用于存储和管理数据库连接。

我认为,出现这种看法是因为**我们在配置数据源的时候,把连接池也进行了相关的配置。**所以才会把数据源等同于连接池。

不过,虽然不是同个东西,但是数据源和连接池是紧密相关的,它们一起协同工作来管理数据库连接并提供访问数据库的功能。

在日常开发中,数据源除了指数据来自哪里,还可以有其他信息!对于数据源对象来说,它定义了数据库连接参数以及连接数据库所需的所有信息,例如数据库服务器的地址、用户名和密码等。

有的连接池,会从数据源对象中获取连接参数并使用它们来创建和管理数据库连接,就比如当我们在项目中使用开源的数据库连接池的时候,就需要进行相关的配置。对于开源的数据库连接池,它们都具有实现 Java 的标准数据源接口 javax.sql.DataSource 的类,可以直接使用。

以 Druid 为例,这个类是 com.alibaba.druid.pool.DruidDataSource,可以用于创建和管理数据库连接。

在我看来,Druid 是一个既包含数据源功能又包含连接池功能的开源项目。它可以用作数据源,通过配置和管理连接池来提供访问数据库的功能。Druid 提供了一组高效的连接池和监控工具,可用于管理和监控数据库连接。

https://github.com/alibaba/druid/wiki/DruidDataSource配置

这里给出 Druid 的一些配置:

 <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <!-- 基本属性 url、user、password --><property name="url" value="${jdbc_url}" /><property name="username" value="${jdbc_user}" /><property name="password" value="${jdbc_password}" /><!-- 配置初始化大小、最小、最大 --><property name="initialSize" value="5" /><property name="minIdle" value="10" /><property name="maxActive" value="20" /><!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 --><property name="timeBetweenEvictionRunsMillis" value="2000" /><!-- 配置一个连接在池中最小生存的时间,单位是毫秒 --><property name="minEvictableIdleTimeMillis" value="600000" /><property name="maxEvictableIdleTimeMillis" value="900000" /></bean>

从上面的配置中可以看到,我们在这里进行了数据源配置,这里不仅仅配置了连接对象连接的是哪一个数据库,它的用户名和用户密码是多少,还配置了数据库连接池的初始化大小、最小和最大连接数等属性。

总结

一开始,我主要说明了数据库和数据库管理系统(DBMS)的区别。虽然我们通常会将 MySQL、Oracle、PostgreSQL 等软件称为数据库,但它们实际上是一种可以操作和管理数据库的软件,而真正的数据库是指存储数据的仓库。

接着,讲了什么是数据库连接池,数据库连接池是一种池化技术,它可以提前准备好一定数量的连接对象并将它们放在一个「池子」中。这些连接对象可以被重复使用,当需要进行数据库操作时,可以从连接池中获取连接对象并执行相关操作。执行完毕后,连接对象会被放回到池子中,以供后续的操作使用。这种技术可以避免频繁地创建和销毁连接对象,从而提高应用程序的性能和效率。

最后,讲了什么是数据源以及它与连接池的关系,它们两者是不同的,或者说有这么三个词:「数据源」、「数据库连接池」、「数据源对象」。单独说数据源,那么就顾名思义,数据的来源。数据库连接池,用于管理连接的,方便连接的复用,提升效率。数据源对象,它包含了连接池的配置,也配置了数据源,即数据从哪里来。

以上,也不知道我又没有说清楚,欢迎大家评论!

最后的最后

希望各位屏幕前的靓仔靓女们给个三连!你轻轻地点了个赞,那将在我的心里世界增添一颗明亮而耀眼的星!

咱们下期再见!


http://www.ppmy.cn/news/47296.html

相关文章

常见分布式锁4:zookeeper 瞬时znode节点 + watcher监听机制,ChatGPT回复的解决死锁的方案

原文地址在这里 临时节点具备数据自动删除的功能。当client与ZooKeeper连接和session断掉时&#xff0c;相应的临时节点就会被删除。zk有瞬时和持久节点&#xff0c;瞬时节点不可以有子节点。会话结束之后瞬时节点就会消失&#xff0c;基于zk的瞬时有序节点实现分布式锁&#x…

科技云报到:存储开源,风雨飘摇下“披着羊皮的狼”?

科技云报道原创。 这些年开源界的风风雨雨&#xff0c;时不时撼动着人们的内心。 2022年&#xff0c;俄乌冲突导致全球最大的独立开源软件公司SUSE、美国开源软件巨头Redhat、主流开源容器引擎Docker&#xff0c;纷纷宣布停止与俄罗斯的合作。 而全球最大的开源及私有代码项目…

socket 及 字节序转换(嵌入式学习)

socket 及 字节序转换 socket简介Socket为什么需要Socket&#xff1f;socket类型Socket通信模型 字节序主机字节序到网络字节序网络字节序到主机字节序IP地址转换 socket简介 1、1982 - Berkeley Software Distributions 操作系统引入了socket作为本地进程之间通信的接口 2、1…

Linux 服务简单优化

硬件优化 处理器&#xff1a;核心数、主频、制程工艺、线程数、缓存等 核心数&#xff1a;1、2、4、6、8、12、24、32等 主频&#xff1a;2.0GHz、2.3GHz等等 制程工艺&#xff1a;22nm、14nm、10nm等等 线程数&#xff1a;1、2 缓存&#xff1a;L1、L2、L3 建议&#xff1a;尽…

Linux用户的分类与家目录,ls、pwd、cd、mkdir、touch、rmdir、rm指令与选项等

Linux中用户的分类与用户的家目录 在Linux当中&#xff0c;用户的分类只分为两类&#xff0c;一类叫做超级用户root&#xff0c;还有就是其他也就是传说中的普通用户。我们刚刚登进去时&#xff0c;默认所处的目录是***/root或者/home/用户名***&#xff0c;比如说/root, /hom…

知识库管理系统对于企业有哪些作用及优势?

知识库管理系统是一种通过集成多种技术手段&#xff0c;将企业内部知识进行收集、整理、存储、分析和共享的信息管理系统。知识库管理系统可以帮助企业管理和利用企业内部的知识&#xff0c;提高企业的创新能力和竞争力。 知识库管理系统的作用 1、促进企业内部知识的流通和共…

无线传感器网络硬件设计简介

无线传感器网络硬件设计简介 无线传感器网络因其巨大的应用前景越来越受到学术界和工业界的广泛关注。本文介绍了无线传感器网络节点的体系结构&#xff0c;分析比较了国内外当前典型的硬件平台&#xff0c;重点讨论了目前无线传感器网络节点常用的处理器、射频芯片、电源和传…

Java IO流

Java IO流 IO就是Intput和Output也就是输入输出&#xff0c;将数据输入到计算机内存的过程叫做输入&#xff0c;从内存读取出来的数据叫做输出。Java的IO流总共有40多个类&#xff0c;他们都是由下个4个抽象类派生出来的&#xff0c;InputStream和Read和OutputStream和Writer。…

网络拥塞控制,对越远的流量越宽容

考虑下面的网络传输场景&#xff1a; ​ S1&#xff0c;S2&#xff0c;S3&#xff0c;S4 向 D 方向发送&#xff0c;R4 发生拥塞。R4 必须丢弃一些数据进行疏导反馈拥塞信号&#xff0c;否则谁也过不去。 优先丢掉离得最近的 S4 的数据&#xff0c;其次依次丢 S3&#xff0c;S2…

ChatGPT会如何改变制造业?

来源 | Smart Industry Edgenesis编译 ChatGPT最新版本的发布成为热门头条。OpenAI表示该版本的ChatGPT能够在多个专业测试中达到“人类水平”的表现&#xff0c;例如司法考试和SAT考试。不过&#xff0c;在工业领域中&#xff0c;ChatGPT能够发挥怎样的作用呢&#xff1f;Sma…

计算广告(十七)

多渠道组合路径效率评价 ​ 编辑切换为居中 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 分析背景&#xff1a; 电商归因分析通常以 last_click 为基准&#xff0c;将成交转化归功于用户完成转化前的最近一个广告系列。然而&#xff0c;在此之前&a…

HTTP的那些事儿

超文本传输协议&#xff08;Hyper Text Transfer Protocol&#xff0c;HTTP&#xff09;&#xff0c;它是在计算机世界中的两个点之间传递文本&#xff0c;图片&#xff0c;多媒体等超文本文件的协议。HTTP处在数据链路层&#xff0c;网络层&#xff0c;传输层&#xff0c;应用…

java 资料地址汇总

1 SpringBoot - 使用 Assert 校验让业务代码更简洁 SpringBoot - 使用 Assert 校验让业务代码更简洁 2 MyBatis-Plus 还手写 Join 联表查询&#xff1f;一个依赖轻松搞定&#xff0c;真香&#xff01; MyBatis-Plus 还手写 Join 联表查询&#xff1f;一个依赖轻松搞定&#…

中小企业面临怎样的数字化转型局面

当前&#xff0c;我国经济长期向好的基本面没有改变&#xff0c;但承受着“需求收缩、供给冲击、预期减弱”的三重压力&#xff0c;中小企业的数字化转型之路较之以往更加艰难、曲折。为帮助中小企业纾困解难、平稳渡过危机&#xff0c;需进一步优化政策“组合拳”&#xff0c;…

CMake

CMake定义 CMake是一个跨平台的安装&#xff08;编译&#xff09;工具&#xff0c;可以用简单的语句来描述所有平台的安装(编译过程)。他能够输出各种各样的makefile或者project文件&#xff0c;能测试编译器所支持的C特性,类似UNIX下的automake。只是 CMake 的组态档取名为 C…

背包问题——01背包|完全背包

目录 前言&背包问题的历史 01背包 1、题目 2、暴力解01背包 Ⅰ、代码 3、动态规划解01背包 Ⅰ、二维dp数组解01背包 1&#xff09;dp数组的含义 2&#xff09;递推公式 3&#xff09;dp数组的初始化 4&#xff09;遍历顺序的讨论 5、代码 Ⅱ、一维数组解01背包 1&…

[API]集合Collection常用方法集合遍历新循环泛型(三)

什么是集合&#xff1a; 集合和数组一样&#xff0c;可以保存一组数据&#xff0c;并且提供了操作数组元素的相关方法&#xff0c;使用用更加方便 集合框架中的相关接口&#xff1a; java.util.Collection接口&#xff1a;是所有集合的顶级接口&#xff0c;封装了所有集合所…

【理解 C++ 中的头文件和源文件的作用 】

include文件中定义 src文件中声明 头文件中应该只放变量和函数的声明&#xff0c;而不能放它们的定义。 在 C 中&#xff0c;头文件和源文件有着不同的作用。它们共同组成了 C 项目的基本结构。让我们逐个了解它们的作用。 头文件&#xff08;.h 或 .hpp 文件&#xff09;&a…

【从零开始学Skynet】实战篇《球球大作战》(十四):agent跨服务器版

至此&#xff0c;我们已完成了《球球大作战》的绝大部分功能&#xff0c;只剩下完 善agent &#xff0c;让它和 scene 服务联动了。 1、多个模块 一般而言&#xff0c;代理服务会承载很多系统&#xff0c;比如邮件、成就等&#xff0c;此处涉及的代码较多&#xff0c;容易混 乱…

初中级测试工程师,软件测试面试题总结大全(功能/接口/自动化测试)你要的都有...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 一般软件测试的面…