程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> MYSQL數據庫 >> MYSQL入門知識 >> 數據庫(MySql)連接詳細講解

數據庫(MySql)連接詳細講解

編輯:MYSQL入門知識
聊聊數據庫(MySql)連接吧,你真的清楚嗎?

前言

說到數據庫連接,這個大家都很熟悉了。但是熟悉一般來自於下面三種情況
* 剛開始學編程的時候,老師就說用完的數據庫連接一定要關閉,不然會有嚴重的後果。
* 編程一段時間後,大家都說要用連接池來優化數據庫連接。
* 編程幾年後,老大們說要考慮一台服務器mysql的並發連接數與負載等。
所以不停留在聽說的層面,深入去學習與研究下mysql的連接機制與.net mysql驅動對連接的管理也挺有必要的。

本文會用到哪些工具

  • vs建立一個web項目,測試連接的建立與回收
  • navicate for mysql(可以看到mysql的連接數的實時監控)
  • nuget安裝mysql.data.dll,.net mysql的驅動
  • **.net reflector* 反編譯查看mysql驅動的源碼
  • fiddler友情客串,測測並發

打開navicate for mysql->選擇“工具”->服務器監控->勾選要監控的服務器
就可以看到這個服務器的實時連接情況,每隔5秒刷新一次。
每打開一個連接多一個,打開數據庫的時候對一個,打開查詢的時候也會多一個

如圖的:1463 1465 1466就是剛才打開的。


一.先說說mysql的最大連接數

在navicate中查詢:show variables like '%max_connections%';
可以看到默認的數值為:max_connections:151

為了便於測試我們修改my.ini文件中的max_connections參數,修改為10。一定要重啟mysql服務才能生效


然後我們運行web項目,當打開頁面的時候執行。注意這裡注釋了關閉連接語句:

這時我們在chrome中訪問頁面,當打開第8個頁面時出現:Too many connections的異常。

為什麼時第8個呢:因為之前說了打開數據庫以及查詢占了3個,所以8+3>10。自然就報mysql異常了。
我們看看服務器的監控:

都連接了2000多秒,還在一直連著,導致其他請求無法建立連接。這就是不釋放連接的最直接的後果。

下面我們來手動結束那些沒有被關閉的連接(右擊連接->結束進程或者停止vs運行)。
接下來測試正常情況,取消連接關閉的注釋

二.你關閉連接的時候,連接真的關閉了嗎?

我們發現訪問網頁後,服務器中多了一個連接,進程id為1479。但是明明執行了connection.Close(),但結果好像不是我們預料的那樣。
等待幾十秒後發現隨著訪問的結束,這個連接的閒置時間為109秒沒有被關閉掉。

但當我們重新打開一個網頁後,發現

這個連接的閒置時間被重置了為0了。
這種現象跟mysql並沒有太多原因,這是由mysql 的.net驅動控制的。當我們調用connection.Close()時,與mysql建立的socket連接被沒有真正的關閉掉,而是被保留並置為空閒狀態。
當新的請求連接過來後,會直接使用這個連接而不會建立新的socket連接。這是mysql驅動自帶的連接池功能,來優化性能與資源。
我們來翻下mysql.data的源代碼:

大部分情況下我們調用connection.Close()只是調用:this.SetState(ConnectionState.Close,true),改變一下連接的狀態而已。並非真的關閉
真正的關閉時調用CloseFully()

mysql驅動申請的連接真正關閉是通過超時實現的。經過測試如果閒置300秒左右,這個連接就會被徹底關閉了

所以交互流程圖是這樣的:

三.斷網了怎麼辦?

正常情況下自然是好,但是如果:

這時候出現的狀況就比未手動關閉數據庫連接還要嚴重,程序已經失去控制權了。會出現一批處於空閒中的數據庫連接無法被正常釋放掉。如果網絡時好時壞,就有可能是一批接一批的。
所以mysql服務內部也有一個超時機制,當一個socket連接長期空閒的時候mysql服務端會強制關閉這個連接。如果等mysql的超時機制來處理的問題,
超時時間通過:show global variables like '%timeout%';

如上圖所示的wait_timeout就是控制等待空閒超時的參數,默認為28800秒也就是8小時

四.連接符中配置的Min Pool Size=?;Max Pool Size=?;驅動是如何管理的?

通常在配置連接字符串的使用連接池,如我們配置
var connection = new MySqlConnection(@"Data Source=121.40.64.127;port=3306; User ID=root;Password=root; database=spring;Persist Security Info=false; Connect Timeout=30;Min Pool Size=2;Max Pool Size=5;");

首先Min Pool Size=2;

運行項目後,會一次多出兩個連接,如下圖:

而且這兩個連接只要iis沒有回收,不會被銷毀

任何請求過來後。只要這兩個連接有空閒,就不會創建新的連接

接著Max Pool Size=5;

如果Min Pool Size設置的數量不夠用,也就是並發量大與2的時候,那麼mysql驅動就會申請更多的連接。
我們來實際測試一下,使用fiddler我們來模擬下“瞬間的大量請求”:

打開fiddler->浏覽器中請求網頁->在filddler找到那個請求->按住shift->點擊菜單中的Replay->輸入50->點擊ok
這樣就會異步同時發出50個請求。


我們看下服務器的監控信息:

這時就會同時創建5個連接,因為2個不夠 5個最大,所以只能創建5各連接供使用,後面的請求只能等其他請求釋放連接以後才能進入處理。
如果你在連接關閉前設置:Thread.Sleep(5000),讓連接延遲5秒再關閉。就能明顯的感覺到大量數據庫請求阻塞,因為沒有額外的連接來處理請求了。
那是不是實際場景中,之前講的max_connectionsMax Pool Size都設置最大好了?
當然不是,服務器的性能有限啊。你設置最大,高並發的時候連接限制倒是沒有,但整個服務器估計就掛了。
繼續剛才的Max Pool Size,申請的五個連接,如果閒置300秒左右。有3個會被回收掉,只會保留Min Pool Size生成的2個。請看截圖

也就是連接符中設置的Min Pool Size會永久的生成兩個連接在那裡,不會被關閉。Max Pool Size只在Min Pool Size不夠的時候生成,用完(閒置超時後)會被關閉掉
程序中無論多少並發請求,mysql驅動提供給當前應用的連接數都不會超過Max Pool Size。這樣看起來Max Pool Size也有保護服務器不被拖垮的作用

未完待續……

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved