「資料庫、資料庫連接池、數據源」這些概念你真的理解了嗎?

来源:https://www.cnblogs.com/god23bin/archive/2023/04/21/concepts-that-you-need-to-understand.html
-Advertisement-
Play Games

我學習的過程中,對於連接池和數據源分得不是很清楚,而且我發現有的人將資料庫等同於數據源,或者將數據源等同於連接池,實際上這些說法並不准確。 ...


前言

我學習的過程中,對於連接池和數據源分得不是很清楚,而且我發現有的人將資料庫等同於數據源,或者將數據源等同於連接池,實際上這些說法並不准確。

在某次工作中,同事 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 等軟體稱為資料庫,但它們實際上是一種可以操作和管理資料庫的軟體,而真正的資料庫是指存儲數據的倉庫。

接著,講了什麼是資料庫連接池,資料庫連接池是一種池化技術,它可以提前準備好一定數量的連接對象並將它們放在一個「池子」中。這些連接對象可以被重覆使用,當需要進行資料庫操作時,可以從連接池中獲取連接對象並執行相關操作。執行完畢後,連接對象會被放回到池子中,以供後續的操作使用。這種技術可以避免頻繁地創建和銷毀連接對象,從而提高應用程式的性能和效率。

最後,講了什麼是數據源以及它與連接池的關係,它們兩者是不同的,或者說有這麼三個詞:「數據源」、「資料庫連接池」、「數據源對象」。單獨說數據源,那麼就顧名思義,數據的來源。資料庫連接池,用於管理連接的,方便連接的復用,提升效率。數據源對象,它包含了連接池的配置,也配置了數據源,即數據從哪裡來。

以上,也不知道我又沒有說清楚,歡迎大家評論!

最後的最後

希望各位屏幕前的靚仔靚女們給個三連!你輕輕地點了個贊,那將在我的心裡世界增添一顆明亮而耀眼的星!

咱們下期再見!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 記錄Docker的-v指令使用 前言 之前我淺學了一下docker,方便部署.net項目(部署的是打包之後的項目) dockerfile文件如下: FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base WORKDIR /app EXPOSE 5031 EX ...
  • 隨著技術的發展,ASP.NET Core MVC也推出了好長時間,經過不斷的版本更新迭代,已經越來越完善,本系列文章主要講解ASP.NET Core MVC開發B/S系統過程中所涉及到的相關內容,適用於初學者,在校畢業生,或其他想從事ASP.NET Core MVC 系統開發的人員。 經過前幾篇文章 ...
  • C#中的IDGen是一個C#實現的Twitter Snowflake演算法的ID生成器,可以生成全局唯一的ID,支持高併發場景下的ID生成。在本篇文章中,我們將介紹IDGen的使用方法並提供相關的C#示例代碼。 IDGen的介紹 IDGen是一款開源的分散式唯一ID生成器,支持多種ID生成演算法,並且可 ...
  • 用過ASP.NET Core MVC中IActionFilter攔截器的開發人員,都知道這是一個非常強大的MVC攔截器。最近才發現IActionFilter的OnActionExecuting方法,甚至可以獲取Controller的Action方法參數值。 假如我們在ASP.NET Core MVC ...
  • 平臺 windows 需 求 由於我近期有一個比賽,而我的主機又是x86架構的,人家要求使用arm架構的主機,我這窮屌絲,不可 能去買一臺吧,而且隨著國產系統的推進,採用arm架構的主機也越來越多,作為運維我們該怎麼利用x86 來運行arm架構的主機成為了一個問題 需 要的軟體和程式 以下軟體版本皆 ...
  • ansible分離部署LNMP 環境說明: | 系統 | 主機名 | IP | 服務 | | | | | | | centos8 | ansible | 192.168.111.141 | ansible主控機 | | centos8 | nginx | 192.168.111.142 | ngin ...
  • ​根據2022年的DevOps全球調查報告顯示,主流軟體企業採用或部分採用DevOps且已獲得良好成效的占比已達70%,DevOps儼然成為當下軟體開發研究的重要方向。 測試作為軟體開發的必要過程,是提升軟體可靠性、保證軟體質量的關鍵環節。然而,從過往研究文獻來看,希望通過DevOps提升軟體交付效 ...
  • 在這裡分享項目中我經常使用的一種串口收發方式:阻塞發送 + 接收中斷 +空閑中斷 + 環形隊列 項目代碼地址:https://gitee.com/Mokun_gitee/stm32_hal_study.git 一、簡介 串口發送使用最簡單的阻塞發送方式,一般來說都是接收的數據量比較大,發送數據用此方 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...