前言
我學習的程序中,對于連接池和資料源分得不是很清楚,而且我發現有的人將資料庫等同于資料源,或者將資料源等同于連接池,實際上這些說法并不準確,
在某次作業中,同事 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 SQLExceptionConnection 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" init-method="init" destroy-method="close">
<!-- 基本屬性 url、user、password -->
<property name="url" value="https://www.cnblogs.com/god23bin/p/${jdbc_url}" />
<property name="username" value="https://www.cnblogs.com/god23bin/p/${jdbc_user}" />
<property name="password" value="https://www.cnblogs.com/god23bin/p/${jdbc_password}" />
<!-- 配置初始化大小、最小、最大 -->
<property name="initialSize" value="https://www.cnblogs.com/god23bin/p/5" />
<property name="minIdle" value="https://www.cnblogs.com/god23bin/p/10" />
<property name="maxActive" value="https://www.cnblogs.com/god23bin/p/20" />
<!-- 配置間隔多久才進行一次檢測,檢測需要關閉的空閑連接,單位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="https://www.cnblogs.com/god23bin/p/2000" />
<!-- 配置一個連接在池中最小生存的時間,單位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="https://www.cnblogs.com/god23bin/p/600000" />
<property name="maxEvictableIdleTimeMillis" value="https://www.cnblogs.com/god23bin/p/900000" />
</bean>
從上面的配置中可以看到,我們在這里進行了資料源配置,這里不僅僅配置了連接物件連接的是哪一個資料庫,它的用戶名和用戶密碼是多少,還配置了資料庫連接池的初始化大小、最小和最大連接數等屬性,
總結
一開始,我主要說明了資料庫和資料庫管理系統(DBMS)的區別,雖然我們通常會將 MySQL、Oracle、PostgreSQL 等軟體稱為資料庫,但它們實際上是一種可以操作和管理資料庫的軟體,而真正的資料庫是指存盤資料的倉庫,
接著,講了什么是資料庫連接池,資料庫連接池是一種池化技術,它可以提前準備好一定數量的連接物件并將它們放在一個「池子」中,這些連接物件可以被重復使用,當需要進行資料庫操作時,可以從連接池中獲取連接物件并執行相關操作,執行完畢后,連接物件會被放回到池子中,以供后續的操作使用,這種技術可以避免頻繁地創建和銷毀連接物件,從而提高應用程式的性能和效率,
最后,講了什么是資料源以及它與連接池的關系,它們兩者是不同的,或者說有這么三個詞:「資料源」、「資料庫連接池」、「資料源物件」,單獨說資料源,那么就顧名思義,資料的來源,資料庫連接池,用于管理連接的,方便連接的復用,提升效率,資料源物件,它包含了連接池的配置,也配置了資料源,即資料從哪里來,
以上,也不知道我又沒有說清楚,歡迎大家評論!
最后的最后
希望各位螢屏前的靚仔靚女們給個三連!你輕輕地點了個贊,那將在我的心里世界增添一顆明亮而耀眼的星!
咱們下期再見!
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/550821.html
標籤:MySQL
上一篇:mysql索引--普通索引,唯一索引,主鍵索引,參照完整性約束,資料完整性約束
下一篇:返回列表
