數(shù)據(jù)庫(kù)連接池

最近項(xiàng)目當(dāng)中一直沒有注意數(shù)據(jù)庫(kù)連接池的問(wèn)題
今天查了些資料鹏秋。做一個(gè)小總結(jié)

從程序當(dāng)中看連接

  • Engine Configuration

Engine 是訪問(wèn)數(shù)據(jù)庫(kù)的入口,Engine引用Connection PoolDialect實(shí)現(xiàn)了對(duì)數(shù)據(jù)庫(kù)的訪問(wèn), Dialect指定了具體的數(shù)據(jù)庫(kù)類型 MYSQL, SQLSERVER等, 三者關(guān)系如圖所示:

file-list

只有當(dāng)調(diào)用connect(),execute()函數(shù)的時(shí)候窍仰,才會(huì)創(chuàng)建數(shù)據(jù)庫(kù)的連接

create_engine

使用 create_engine創(chuàng)建我們需要的DB starting point

from sqlalchemy import create_engine

scheme = 'mysql+pymysql://root:123456@localhost:3306/dev_shopping?charset=utf8'
engine = create_engine(scheme, pool_size=10 , max_overflow=-1, pool_recycle=1200)

create_engine 函數(shù)常用參數(shù):

pool_size=10 # 連接池的大小,0表示連接數(shù)無(wú)限制

pool_recycle=-1 # 連接池回收連接的時(shí)間,如果設(shè)置為-1阱飘,表示沒有no timeout, 注意,mysql會(huì)自動(dòng)斷開超過(guò)8小時(shí)的連接虱颗,所以sqlalchemy沿用被mysql斷開的連接會(huì)拋出MySQL has gone away

max_overflow=-1 # 連接池中允許‘溢出’的連接個(gè)數(shù)沥匈,如果設(shè)置為-1,表示連接池中可以創(chuàng)建任意數(shù)量的連接

pool_timeout=30 # 在連接池獲取一個(gè)空閑連接等待的時(shí)間

echo=False # 如果設(shè)置True, Engine將會(huì)記錄所有的日志忘渔,日志默認(rèn)會(huì)輸出到sys.stdout

創(chuàng)建Engine之后高帖,接下來(lái)的問(wèn)題,就是如何使用Engine

在單進(jìn)程中畦粮,建議在在初始化的模塊的時(shí)候創(chuàng)建Engine, 使Engine成為全局變量散址, 而不是為每個(gè)調(diào)用Engine的對(duì)象或者函數(shù)中創(chuàng)建, Engine不同于connect, connect函數(shù)會(huì)創(chuàng)建數(shù)據(jù)庫(kù)連接的資源,Engine是管理connect創(chuàng)建的連接資源

在多進(jìn)程中宣赔,為每個(gè)子進(jìn)程都創(chuàng)建各自的Engine, 因?yàn)檫M(jìn)程之間是不能共享Engine

connect

使用connect 創(chuàng)建連接數(shù)據(jù)庫(kù)資源, 如上所說(shuō)预麸,即使創(chuàng)建了Engine, 還是沒有創(chuàng)建對(duì)數(shù)據(jù)庫(kù)的連接,調(diào)用connect才會(huì)創(chuàng)建真正的連接

connection = engine.connect()
result = connection.execute("select * from tmp")
print type(result) # <class 'sqlalchemy.engine.result.ResultProxy'>
for row in result:
    print "target_name:", row['target_name']
connection.close()

這里有兩個(gè)問(wèn)題需要搞清楚儒将,result返回對(duì)象類型和對(duì)象提供的方法吏祸,第二個(gè)是close函數(shù)調(diào)用之后,發(fā)生了什么事情钩蚊,先說(shuō)close

close

當(dāng)調(diào)用connection.close()之后贡翘,由connect函數(shù)創(chuàng)建的連接會(huì)被釋放到連接池中, 可以供下次使用.

上面這段代碼可以簡(jiǎn)寫為:

result = engine.execute("select username from users")
for row in result:
    print "username:", row['username']

execute函數(shù)會(huì)創(chuàng)建自己的連接蹈矮,并執(zhí)行聲明的sql語(yǔ)句,返回ResultProxy對(duì)象鸣驱,在這個(gè)情況下泛鸟,ResultProxy會(huì)有個(gè)標(biāo)記close_with_result, 如果ResultProxy的值被全部取出來(lái)踊东,Engine會(huì)自動(dòng)close本次連接北滥,并把連接釋放到連接池里面去

如果ResultProxy里面還有數(shù)據(jù)沒有取出來(lái)(rows remaining),可使用result.close()釋放本次連接递胧,如果沒有使用result.close()釋放連接碑韵,python garbage collection 最終為釋放本次連接到連接池中

ResultProxy

現(xiàn)在來(lái)看一下execute()執(zhí)行之后返回的結(jié)果類型 詳細(xì)文檔

常用的API如下:

fetchone() 取出一行缎脾, 當(dāng)所有的行被取出來(lái)之后 connect resource會(huì)被釋放到連接池中祝闻,再次調(diào)用fetchone()將返回None

result = connection.execute("select * from tmp")

row = result.fetchone()
print row[0] # access via integer position
print row['id'] # access via name
print type(row) # <class 'sqlalchemy.engine.result.RowProxy'>

# 類似還有
first()  獲取第一行,同時(shí)無(wú)條件的釋放連接
scalar() 獲取第一行第一列的數(shù)據(jù)遗菠,同時(shí)無(wú)條件的釋放連接
rowcount 獲取row count
lastrowid 使用insert()方法的時(shí)候联喘,獲取最后一行的id

連接池

在這種情況下,當(dāng)你使用了session后就算顯式地調(diào)用session.close()辙纬,也不能把連接關(guān)閉豁遭。連接會(huì)由QueuePool連接池進(jìn)行管理并復(fù)用。

從mysql角度看連接

  • mysql查看當(dāng)前連接數(shù)的命令是 show processlist;
    show processlist;查看正在運(yùn)行的線程贺拣,列出前100條
    show full processlist;列出所有蓖谢。
    +--------+-------------+-------------+---------+-------------+---------+------------------------------------------
    | Id | User | Host | db | Command | Time | State | Info | Progress
    +--------+-------------+-------------+---------+-------------+---------+------------------------------------------
    Id 標(biāo)識(shí),kill某個(gè)mysql線程時(shí)使用
    User 顯示當(dāng)前用戶譬涡,如果不是root闪幽,那么就只顯示授權(quán)范圍內(nèi)的sql語(yǔ)句的用戶
    host 顯示sql語(yǔ)句是從哪個(gè)ip,哪個(gè)端口發(fā)出的涡匀,可以用來(lái)追蹤出問(wèn)題的用戶和端口
    db 顯示該線程連接的是哪個(gè)數(shù)據(jù)庫(kù)
    command 顯示當(dāng)前執(zhí)行的命令盯腌,
    一般:sleep 休眠,query 查詢陨瘩,connect 連接腕够。
    time 狀態(tài)持續(xù)時(shí)間,單位秒
    state 顯示使用當(dāng)前連接的sql語(yǔ)句的狀態(tài)舌劳,很重要列帚湘。請(qǐng)注意,state只是語(yǔ)句執(zhí)行中的某一個(gè)狀態(tài)甚淡。以查詢?yōu)槔兔牵枰?jīng)過(guò)copying to tmp table,sorting result材诽,sending data等狀態(tài)才算完成底挫。
    info 顯示這個(gè)sql語(yǔ)句,判斷問(wèn)題的重要依據(jù)脸侥。

最關(guān)鍵的參數(shù)就是state列建邓,狀態(tài)主要有:
Checking table
 正在檢查數(shù)據(jù)表(這是自動(dòng)的)。
Closing tables
 正在將表中修改的數(shù)據(jù)刷新到磁盤中睁枕,同時(shí)正在關(guān)閉已經(jīng)用完的表官边。這是一個(gè)很快的操作,如果不是這樣的話外遇,就應(yīng)該確認(rèn)磁盤空間是否已經(jīng)滿了或者磁盤是否正處于重負(fù)中注簿。
Connect Out
 復(fù)制從服務(wù)器正在連接主服務(wù)器。
Copying to tmp table on disk
 由于臨時(shí)結(jié)果集大于tmp_table_size跳仿,正在將臨時(shí)表從內(nèi)存存儲(chǔ)轉(zhuǎn)為磁盤存儲(chǔ)以此節(jié)省內(nèi)存诡渴。
Creating tmp table
 正在創(chuàng)建臨時(shí)表以存放部分查詢結(jié)果。
deleting from main table
 服務(wù)器正在執(zhí)行多表刪除中的第一部分菲语,剛刪除第一個(gè)表妄辩。
deleting from reference tables
 服務(wù)器正在執(zhí)行多表刪除中的第二部分,正在刪除其他表的記錄山上。
Flushing tables
 正在執(zhí)行FLUSH TABLES眼耀,等待其他線程關(guān)閉數(shù)據(jù)表。
Killed
 發(fā)送了一個(gè)kill請(qǐng)求給某線程佩憾,那么這個(gè)線程將會(huì)檢查kill標(biāo)志位哮伟,同時(shí)會(huì)放棄下一個(gè)kill請(qǐng)求。MySQL會(huì)在每次的主循環(huán)中檢查kill標(biāo)志位妄帘,不過(guò)有些情況下該線程可能會(huì)過(guò)一小段才能死掉楞黄。如果該線程程被其他線程鎖住了,那么kill請(qǐng)求會(huì)在鎖釋放時(shí)馬上生效寄摆。
Locked
 被其他查詢鎖住了谅辣。
Sending data
 正在處理SELECT查詢的記錄,同時(shí)正在把結(jié)果發(fā)送給客戶端婶恼。
Sorting for group
 正在為GROUP BY做排序桑阶。
 Sorting for order
 正在為ORDER BY做排序。
Opening tables
 這個(gè)過(guò)程應(yīng)該會(huì)很快勾邦,除非受到其他因素的干擾蚣录。例如,在執(zhí)ALTER TABLE或LOCK TABLE語(yǔ)句行完以前眷篇,數(shù)據(jù)表無(wú)法被其他線程打開萎河。正嘗試打開一個(gè)表吭历。
Removing duplicates
 正在執(zhí)行一個(gè)SELECT DISTINCT方式的查詢,但是MySQL無(wú)法在前一個(gè)階段優(yōu)化掉那些重復(fù)的記錄作彤。因此灯帮,MySQL需要再次去掉重復(fù)的記錄,然后再把結(jié)果發(fā)送給客戶端擎椰。
Reopen table
 獲得了對(duì)一個(gè)表的鎖支子,但是必須在表結(jié)構(gòu)修改之后才能獲得這個(gè)鎖。已經(jīng)釋放鎖达舒,關(guān)閉數(shù)據(jù)表值朋,正嘗試重新打開數(shù)據(jù)表。
Repair by sorting
 修復(fù)指令正在排序以創(chuàng)建索引巩搏。
Repair with keycache
 修復(fù)指令正在利用索引緩存一個(gè)一個(gè)地創(chuàng)建新索引昨登。它會(huì)比Repair by sorting慢些。
Searching rows for update
 正在講符合條件的記錄找出來(lái)以備更新贯底。它必須在UPDATE要修改相關(guān)的記錄之前就完成了丰辣。
Sleeping
 正在等待客戶端發(fā)送新請(qǐng)求.
System lock
 正在等待取得一個(gè)外部的系統(tǒng)鎖。如果當(dāng)前沒有運(yùn)行多個(gè)mysqld服務(wù)器同時(shí)請(qǐng)求同一個(gè)表丈甸,那么可以通過(guò)增加--skip-external-locking參數(shù)來(lái)禁止外部系統(tǒng)鎖糯俗。
Upgrading lock
 INSERT DELAYED正在嘗試取得一個(gè)鎖表以插入新記錄。
Updating
 正在搜索匹配的記錄睦擂,并且修改它們得湘。
User Lock
 正在等待GET_LOCK()。
Waiting for tables
 這個(gè)是我經(jīng)常會(huì)遇到的顿仇,意思是該線程得到通知淘正,數(shù)據(jù)表結(jié)構(gòu)已經(jīng)被修改了,需要重新打開數(shù)據(jù)表以取得新的結(jié)構(gòu)臼闻。然后鸿吆,為了能的重新打開數(shù)據(jù)表,必須等到所有其他線程關(guān)閉這個(gè)表述呐。以下幾種情況下會(huì)產(chǎn)生這個(gè)通知:FLUSH TABLES tbl_name, ALTER TABLE, RENAME TABLE, REPAIR TABLE, ANALYZE TABLE,或OPTIMIZE TABLE惩淳。
waiting for handler insert
 INSERT DELAYED已經(jīng)處理完了所有待處理的插入操作,正在等待新的請(qǐng)求乓搬。
 大部分狀態(tài)對(duì)應(yīng)很快的操作思犁,只要有一個(gè)線程保持同一個(gè)狀態(tài)好幾秒鐘,那么可能是有問(wèn)題發(fā)生了进肯,需要檢查一下激蹲。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市江掩,隨后出現(xiàn)的幾起案子学辱,更是在濱河造成了極大的恐慌,老刑警劉巖策泣,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異着降,居然都是意外死亡差油,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門任洞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)发侵,“玉大人交掏,你說(shuō)我怎么就攤上這事刃鳄≈殉冢” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵叔锐,是天一觀的道長(zhǎng)挪鹏。 經(jīng)常有香客問(wèn)我愉烙,道長(zhǎng),這世上最難降的妖魔是什么步责? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮蔓肯,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘秉扑。我一直安慰自己,他們只是感情好舟陆,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布旧噪。 她就那樣靜靜地躺著,像睡著了一般淘钟。 火紅的嫁衣襯著肌膚如雪陪毡。 梳的紋絲不亂的頭發(fā)上勾扭,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音妙色,去河邊找鬼。 笑死身辨,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的号俐。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼吏饿,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蔬浙!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起畴博,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤绎晃,失蹤者是張志新(化名)和其女友劉穎蜜唾,沒想到半個(gè)月后庶艾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體袁余,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡咱揍,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了煤裙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡且蓬,死狀恐怖题翰,靈堂內(nèi)的尸體忽然破棺而出诈胜,到底是詐尸還是另有隱情,我是刑警寧澤焦匈,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布昵仅,位于F島的核電站,受9級(jí)特大地震影響摔笤,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜籍茧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一寞冯、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧吮龄,春花似錦咆疗、人聲如沸漓帚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)昧辽。三九已至,卻和暖如春搅荞,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背咕痛。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工喇嘱, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人者铜。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓放椰,卻偏偏與公主長(zhǎng)得像悔据,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子科汗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345