关于后端:数据库数据库连接池数据源这些概念你真的理解了吗

37次阅读

共计 6640 个字符,预计需要花费 17 分钟才能阅读完成。

前言

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

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

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

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

以上,也不晓得我又没有说分明,欢送大家评论!

最初的最初

心愿各位屏幕前的 靓仔靓女们 给个三连!你轻轻地点了个赞,那将在我的心里世界削减一颗亮堂而夺目的星!

咱们下期再见!

正文完
 0