WebServer -- 數據庫連接池

目錄

🎂基礎知識

🚩整體內容

🌼單例模式創建

🎂連接池(代碼實現)

初始化

獲取 && 釋放連接

銷毀連接池

🍑RAII 機制釋放數據庫連接

定義

實現


🎂基礎知識

什么是數據庫連接池?

池是一組資源的集合,這組資源在服務器啟動之初,就被完全創建好并初始化

通俗來說,池是資源的容器,本質上是對資源的復用

顧名思義,連接池中的資源為一組數據庫連接,由程序動態的對池中的連接進行使用 / 釋放

當系統開始處理客戶請求時,如果它需要相關的資源,可以直接從池中獲取,無需動態分配;

當服務器處理完一個客戶連接后,可以把相關資源放回池中,無需執行系統調用釋放資源

數據庫訪問的一般流程是什么?

當系統需要訪問數據庫時,先系統創建數據庫連接,完成數據庫操作,然后系統斷開數據庫連接

為什么要創建連接池?

從一般流程看,若系統需要頻繁訪問數據庫,則需要頻繁創建和斷開數據庫連接,

而創建數據庫連接,是一個很耗時的操作,也容易對數據庫造成安全隱患

在程序初始化的時候,集中創建多個數據庫連接,并把它們集中管理,供程序使用,可以保證較快的數據庫讀寫速度,更加安全可靠

🚩整體內容

概述

池可以看作資源的容器,有多種實現方法:數組,鏈表,隊列...

這里,使用 單例模式 和 鏈表 創建數據庫連接池,實現對數據庫連接資源的復用

TinyWebserver 中,數據庫模塊分 2 部分:

1)數據庫連接池的定義

2)利用連接池完成登錄注冊的校驗功能

具體地,工作線程從數據庫連接池取得一個連接,訪問數據庫中的數據,訪問完畢后將連接交還連接池

內容

本博客介紹數據庫連接池的定義,具體涉及到:單例模式的創建,連接池代碼的實現,RAII 機制釋放數據庫連接

  • 單例模式創建
    描述連接池的單例實現
  • 連接池代碼實現
    對連接池的外部外文接口的理解
  • RAII 機制釋放數據庫連接
    描述連接釋放的封裝邏輯

🌼單例模式創建

使用局部靜態變量懶漢模式創建連接池

class connection_pool
{
public:// 局部靜態變量單例模式static connection_pool *GetInstance();private:connection_pool();~connection_pool();
};// 類外實現
connection_pool *connection_pool::GetInstance()
{static connection_pool connPool;return &connPool;
}

🎂連接池(代碼實現)

連接池的定義中注釋比較詳細,這里僅對其實現進行解析

連接池的功能:初始化,獲取連接,釋放連接,銷毀連接池

初始化

值得注意的是,銷毀連接池沒有直接被外部調用,而是通過 RAII 機制來完成自動釋放;

使用信號量實現多線程爭奪連接的同步機制,這里將信號量初始化為數據庫的連接總數

// 構造函數,初始化連接池中的連接數量
connection_pool::connection_pool()
{this->CurConn = 0; // 當前連接數this->FreeConn = 0; // 空閑連接數
}// 析構函數,銷毀連接池
connection_pool::~connection_pool()
{DestroyPool(); // 銷毀連接池
}// 初始化連接池
void connection_pool::init(string url, string User, string PassWord,string DBName, int Port, unsigned int MaxConn)
{// 初始化數據庫信息this->url = url; // 數據庫地址this->Port = Port; // 數據庫端口this->User = User; // 用戶名this->PassWord = PassWord; // 密碼this->DatabaseName = DBName; // 數據庫名稱// 創建 MaxConn 條數據庫連接for (int i = 0; i < MaxConn; i++) {MYSQL *con = NULL; // MySQL 連接指針con = mysql_init(con); // 初始化連接if (con == NULL) {cout << "Error:" << mysql_error(con); // 輸出錯誤信息exit(1); // 退出程序}con = mysql_real_connect(con, url.c_Str(), User.c_str(),DBName.c_str(), Port, NULL, 0); // 連接數據庫if (con == NULL) {cout << "Error: " << mysql_error(con); // 輸出錯誤信息exit(1); // 退出程序}// 更新連接池和空閑連接數量connList.push_back(con); // 將連接添加到連接池列表++FreeConn; // 空閑連接數加一}// 信號量初始化為最大連接數reserve = sem(FreeConn);this->MaxConn = FreeConn; // 最大連接數等于空閑連接數
}

獲取 && 釋放連接

當線程數量大于數據庫連接數量,使用信號量進行同步,每次取出連接,信號量原子 -1,釋放連接原子 +1;若連接池內沒有連接了,則阻塞等待

另外,由于多線程操作連接池,會造成競爭,這里用 互斥鎖 完成同步,具體的同步機制均使用 lock.h 中封裝好的類

// 當有請求時,從數據庫連接池返回一個可用連接,
// 更新使用和空閑連接數
MYSQL *connection_pool::GetConnection()
{MYSQL *con = NULL; // MySQL 連接指針if (0 == connList.size()) // 如果連接池為空,返回空指針return NULL;// 取出連接,信號量原子 -1,為 0 則等待reserve.wait(); // 等待信號量lock.lock(); // 加鎖con = connList.front(); // 獲取連接池中的第一個連接connList.pop_front(); // 彈出連接// 這里兩個變量,沒有用到,雞肋啊...--FreeConn; // 空閑連接數減一++CurConn; // 當前連接數加一lock.unlock(); // 解鎖return con; // 返回連接
}// 釋放當前使用的連接
bool connection_pool::ReleaseConnection(MYSQL *con)
{if (NULL == con) // 如果連接為空,返回falsereturn false;lock.lock(); // 加鎖connList.push_back(con); // 將連接放回連接池++FreeConn; // 空閑連接數加一--CurConn; // 當前連接數減一lock.unlock(); // 解鎖// 釋放連接原子 +1reserve.post(); // 釋放信號量return true; // 返回true
}

銷毀連接池

1)通過 迭代器 遍歷連接池鏈表

2)關閉對應數據庫連接

3)清空鏈表

4)并重置空閑連接和現有連接數量

// 銷毀數據庫連接池
void connection_pool::DestroyPool()
{lock.lock(); // 加鎖if (connList.size() > 0) { // 如果連接池不為空// 迭代器遍歷,關閉數據庫連接list<MYSQL *>::iterator it; // 聲明迭代器it,用于遍歷connList列表for (it = connList.begin(); it != connList.end(); ++it) // 遍歷連接池中的每個連接{MYSQL *con = *it; // 獲取迭代器指向的連接mysql_close(con); // 關閉數據庫連接}CurConn = 0; // 將當前連接數設置為0FreeConn = 0; // 將空閑連接數設置為0// 清空listconnList.clear(); // 清空連接池列表lock.unlock(); // 解鎖}// 無論是否進入 if 分支,都能正確釋放互斥鎖lock.unlock(); // 解鎖
}

🍑RAII 機制釋放數據庫連接

數據庫連接的獲取與釋放通過 RAII 機制封裝,避免手動釋放

定義

需要注意的是,獲取連接時,通過有參構造對傳入的參數進行修改;

其中,數據庫連接本身是指針類型,所以參數需要通過雙指針才能對其進行修改

雙指針:指向指針的指針,避免暴露指針內部細節?

class connectionRAII {
public:// 雙指針對 MYSQL *con 修改connectionRAII(MYSQL **con, connection_pool *connPool); // 構造函數,傳入雙指針用于修改MYSQL *con~connectionRAII(); // 析構函數private:MYSQL *conRAII; // 數據庫連接指針connection_pool *poolRAII; // 連接池指針
};

實現

?不直接調用? 獲取和釋放連接的接口,將其封裝起來,通過 RAII 機制進行獲取和釋放

connectionRAII::connectionRAII(MYSQL **SQL, connection_pool *connPool)
{// 通過雙指針傳入的MYSQL **SQL,將其指向連接池中獲取的連接*SQL = connPool->GetConnection();// 將獲取到的連接賦值給conRAII數據庫連接指針conRAII = *SQL;// 將傳入的連接池指針賦值給poolRAIIpoolRAII = connPool;
}// 析構函數,用于釋放連接
connectionRAII::~connectionRAII()
{// 通過連接池指針釋放連接conRAIIpoolRAII->ReleaseConnection(conRAII);
}

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/715662.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/715662.shtml
英文地址,請注明出處:http://en.pswp.cn/news/715662.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

使用 Docker 部署 Answer 問答平臺

1&#xff09;介紹 GitHub&#xff1a;https://github.com/apache/incubator-answer Answer 問答社區是在線平臺&#xff0c;讓用戶提出問題并獲得回答。用戶可以發布問題并得到其他用戶的詳細答案、建議或信息。回答可以投票或評分&#xff0c;有助于確定有用的內容。標簽和分…

Ps:歷史記錄面板

Ps菜單&#xff1a;窗口/歷史記錄 Window/History 歷史記錄 History面板提供了對圖像編輯過程中所進行更改的深入控制&#xff0c;可以讓用戶回溯并查看每一步操作&#xff0c;從而允許用戶輕松撤銷錯誤或比較不同的編輯效果。 ◆ ◆ ◆ 常用操作方法與技巧 “歷史記錄”面板…

CentOS7設置虛擬機語言為中文

1.查看本地安裝的語言 locale -a 是一個Linux命令&#xff0c;用于列出系統中可用的所有區域設置&#xff08;locales&#xff09;它包含了各種語言和地區的不同設置。 打開終端&#xff08;右鍵open terminal&#xff09;輸入 locale -a 查看本地安裝的語言&#xff1a; 其中z…

如何在Unity項目中使用Plastic SCM進行版本控制

引言 Plastic SCM是一個版本控制系統&#xff0c;專為處理大型項目而設計&#xff0c;特別適用于游戲開發中的Unity項目。它提供了強大的分支和合并工具&#xff0c;使團隊能夠高效地協作開發。 安裝和設置 安裝Plastic SCM 訪問Plastic SCM官網下載客戶端。根據您的操作系…

一些可以訪問gpt的方式

1、Coze扣子是新一代 AI 大模型智能體開發平臺。整合了插件、長短期記憶、工作流、卡片等豐富能力&#xff0c;扣子能幫你低門檻、快速搭建個性化或具備商業價值的智能體&#xff0c;并發布到豆包、飛書等各個平臺。https://www.coze.cn/ 2、https://poe.com/ 3、插件阿里…

EasyRecovery16電腦硬盤數據恢復軟件功能詳解

在數字化時代&#xff0c;人們在日常生活和工作中越來越依賴于電腦和移動設備。不管是個人用戶還是企業&#xff0c;數據的重要性都不言而喻。然而&#xff0c;數據丟失和損壞的風險也隨之增加&#xff0c;因此&#xff0c;數據恢復軟件的需求也日益增長。 EasyRecovery 16是一…

不同材質的油封及其使用溫度限制

油封&#xff0c;也稱為旋轉軸密封件&#xff0c;是防止潤滑油從機器和軸承內部間隙泄漏的重要部件。油封的有效性很大程度上取決于其承受運行過程中所暴露溫度的能力。 材料問題&#xff1a;不同材料及其溫度限制 制造油封所使用的不同材料可以承受不同的溫度范圍。這里有一…

【打工日常】使用docker部署在線Photopea用于linux下替代ps

一、Photopea介紹 linux沒有ps適配&#xff0c;對于有時候工作來說確實不方便&#xff0c;我找了很久&#xff0c;才找到了一款功能可以跟ps接近的在線軟件&#xff0c;使用docker部署就可以了。它是ps的最佳替代品之一&#xff0c;其界面幾乎與ps相同&#xff0c;只不過它是在…

Springboot+vue的醫藥管理系統(有報告)。Javaee項目,springboot vue前后端分離項目。

演示視頻&#xff1a; Springbootvue的醫藥管理系統&#xff08;有報告&#xff09;。Javaee項目&#xff0c;springboot vue前后端分離項目。 項目介紹&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三層…

云軸科技ZStack與華東師范大學共建產教融合基地

近日&#xff0c;上海云軸信息科技有限公司&#xff08;云軸科技ZStack&#xff09;與華東師范大學上海國際首席技術官學院宣布&#xff0c;共同打造產教融合基地&#xff0c;以促進人才培養與產業需求的全方位融合。這一舉措旨在深化教育與產業的合作關系&#xff0c;培養更多…

實戰 | 使用YOLOv8圖像分割實現路面坑洞檢測(步驟 + 代碼)

導 讀 本文主要介紹使用YOLOv8圖像分割實現路面坑洞檢測&#xff08;步驟 代碼&#xff09;。 背 景 如上圖所示&#xff0c;現實生活中路面坑洞對車輛和駕駛員安全來說存在巨大隱患&#xff0c;本文將介紹如何使用YoloV8圖像分割技術來檢測路面坑洞&#xff0c;從而提示駕…

計算機網絡|Socket

文章目錄 Socket并發socket Socket Socket是一種工作在TCP/IP協議棧上的API。 端口用于區分不同應用&#xff0c;IP地址用于區分不同主機。 以下是某一個服務器的socket代碼。 其中with是python中的一個語法糖&#xff0c;代表當代碼塊離開with時&#xff0c;自動對s進行銷毀…

JS:原型與原型鏈(附帶圖解與代碼)

一、原型 寫在前面&#xff1a; 任何對象都有原型。 函數也是對象&#xff0c;所以函數也有原型。 1.什么是原型 在 JavaScript 中&#xff0c;對象有一個特殊的隱藏屬性 [[Prototype]]&#xff0c;它要么為 null&#xff0c;要么就是對另一個對象的引用&#xff0c;該對象…

什么是片內片間均勻性?

均勻性在芯片制程的每一個工序中都需要考慮到&#xff0c;包括薄膜沉積&#xff0c;刻蝕&#xff0c;光刻&#xff0c;cmp&#xff0c;離子注入等。較高的均勻性才能保證芯片的產品與性能。那么片內和片間非均勻性是什么&#xff1f;如何計算&#xff1f;有什么作用呢&#xff…

遞歸與遞推(藍橋杯 c++)

目錄 題目一&#xff1a; 代碼&#xff1a; 題目二: 代碼&#xff1a; 題目三&#xff1a; 代碼&#xff1a; 題目四&#xff1a; 代碼&#xff1a; 題目一&#xff1a; 代碼&#xff1a; #include<iostream> #include<cstring> using namespace std; int …

react Provider Consumer 使用方法

相關文章 React Context的使用方法 跨幾個組件傳遞值或者方法的時候, 如果依賴父子組件傳值, 那勢必會很麻煩. 好在react提供了Provider 和 Consumer 1 調用react的createContext()方法, 產生生產者和消費者組件. // context.js import React from react let { Consumer, Pr…

node.js最準確歷史版本下載

先進入官網:Node.js https://nodejs.org/en 嫌其他博客多可以到/release下載:Node.js,在blog后面加/release https://nodejs.org/en/blog/release/ 點擊next翻頁,同樣的道理

數據結構:棧和隊列(隊列)

隊列的性質 一端進,從另一端出,先進的數據一定先出去,進數據的一端叫隊尾,出數據的一端叫隊頭 特點 保障公平性的排隊 #pragma once #include<stdlib.h> #include<stdbool.h> #include<assert.h>typedef int QDataType; typedef struct QueueNode {int v…

設計模式-結構型模式-外觀模式

外觀模式&#xff08;Facade&#xff09;&#xff0c;為子系統中的一組接口提供一個一致的界面&#xff0c;此模式定義了一個高層接口&#xff0c;這個接口使得這一子系統更加容易使用。[DP] 首先&#xff0c;定義子系統的各個組件接口和具體實現類&#xff1a; // 子系統組件接…

【C++】深入理解C++虛函數與純虛函數

文章目錄 一、虛函數&#xff08;Virtual Function&#xff09;1.1 定義和作用1.2 實現原理1.3 示例代碼1.4 虛函數的重寫定義規則注意事項示例 1.5 基類和派生類的虛函數表**示例理解** 二、純虛函數&#xff08;Pure Virtual Function&#xff09;2.1 定義和作用2.2 示例代碼…