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

前言

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

在某次工作中,同事 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 等软件称为数据库,但它们实际上是一种可以操作和管理数据库的软件,而真正的数据库是指存储数据的仓库。

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

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

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

最后的最后

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

咱们下期再见!

原文链接:https://www.cnblogs.com/god23bin/p/concepts-that-you-need-to-understand.html

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:「数据库、数据库连接池、数据源」这些概念你真的理解了吗? - Python技术站

(0)
上一篇 2023年4月19日
下一篇 2023年4月22日

相关文章

  • MySQL 如何实现表的创建、复制、修改与删除

    MySQL中如何利用代码完成表的创建、复制、修改和删除?下面总结了在创建表的时候各字段的含义以及注意哪些问题,复制和修改及删除常用的代码。 MySQL中如何利用代码完成表的创建、复制、修改和删除?下面总结了在创建表的时候各字段的含义以及注意哪些问题,复制和修改及删除常用的代码。 一、创建表 –创建新表,如果存在则覆盖 drop table [if exis…

    MySQL 2023年4月12日
    00
  • Mysql性能优化案例 – 覆盖索引分享

    下面我来详细讲解“Mysql性能优化案例 – 覆盖索引分享”的完整攻略。 什么是覆盖索引 在 MySQL 中,如果使用了索引的列恰好是查询列,那么就称该索引覆盖了查询,叫做覆盖索引。 具体地说,覆盖索引指对于一条 SQL 语句,查询列的所有数据都可以从索引中获取,而不必访问表中的数据行。这种情况下,查询效率可以达到最大化。 为什么需要覆盖索引 因为 MySQ…

    MySQL 2023年5月19日
    00
  • 最新版MySQL 8.0.22下载安装超详细教程(Windows 64位)

    以下是针对“最新版MySQL 8.0.22下载安装超详细教程(Windows 64位)”的完整攻略: 下载MySQL 8.0.22 访问MySQL官网,从中选择最新的适合你系统(这里选择的是Windows (x86, 64-bit), ZIP Archive)的MySQL 8.0.22版本,点击下载. 安装MySQL 8.0.22 安装MySQL 8.0.2…

    MySQL 2023年5月18日
    00
  • mysql 8.0.17 解压版安装配置方法图文教程

    下面是关于“mysql 8.0.17 解压版安装配置方法图文教程”的完整攻略: 背景说明 MySQL是一款强大的开源关系型数据库管理系统,是许多网站和应用程序背后的基石。MySQL 8.0.17是MySQL官方最新发布的稳定版本,其中的新功能和改进可以提高MySQL的性能和安全性。 步骤一:下载MySQL 8.0.17解压版 首先,我们需要从MySQL官方网…

    MySQL 2023年5月18日
    00
  • Mysql索引覆盖如何实现

    这篇“Mysql索引覆盖如何实现”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Mysql索引覆盖如何实现”文章吧。 1.什么是覆盖索引 通常情况下,我们创建索引的时候只关注where条件,不过这只是索引优化的一个方向。优秀的索引设计应该纵观整个…

    MySQL 2023年4月11日
    00
  • mysql模糊查询1,11,111用逗号(其他符号)拼接的相似字符串

    mysql进行模糊查询时,基本都是LIKE “%sss%”,有时候这种查询时准确的,但是有种情况这种查询会出现很大问题。 看一下下面这张表 如果想查询字段test包含1的数据,一般我们会用常规方式查询,如下: SELECT * FROM c_test WHERE test LIKE “%1%” 但是查询结果不尽人意,如下:   不仅把包含1的查出来了,包含1…

    MySQL 2023年4月13日
    00
  • 阿里云安装mysql数据库出现2002错误解决办法

    针对“阿里云安装mysql数据库出现2002错误解决办法”,我来给一个详细的攻略: 问题 在安装阿里云服务器上的mysql数据库过程中,可能会出现2002错误,导致无法正常安装数据库。 原因 该错误一般是由于数据库服务没有启动或者服务连接配置出现了问题导致。 解决办法 以下是两种解决办法: 解决办法一:启动mysql服务 打开终端,通过以下命令确认mysql…

    MySQL 2023年5月18日
    00
  • MySQL单表百万数据记录分页性能优化技巧

    针对“MySQL单表百万数据记录分页性能优化技巧”的完整攻略,我会给出以下几个方面的讲解: MySQL分页查询的本质 MySQL分页查询性能优化的基本思路 MySQL分页查询性能优化的具体技巧 一、MySQL分页查询的本质 在MySQL中进行分页查询,本质上是从整个数据集中返回一部分记录。这个过程中,需要遵循两个原则:一是尽量减少整个数据集的扫描量,二是尽量…

    MySQL 2023年5月19日
    00
合作推广
合作推广
分享本页
返回顶部