之前遇到過(guò)這么一種情況:
連接數(shù)據(jù)庫(kù)的部分Session會(huì)出現(xiàn)不定時(shí)的阻塞,這種阻塞時(shí)長(zhǎng)時(shí)短,有時(shí)候持續(xù)較長(zhǎng)時(shí)間,有時(shí)間持續(xù)時(shí)間較短,沒(méi)有什么規(guī)律。
之后分析相關(guān)存儲(chǔ)過(guò)程和代碼寫(xiě)法,發(fā)現(xiàn)是阻塞源頭的存儲(chǔ)過(guò)程中開(kāi)啟了事務(wù),而應(yīng)用程序在調(diào)用存儲(chǔ)過(guò)程發(fā)生異常之后沒(méi)有進(jìn)行特別的處理(提交或者回滾),
那么在執(zhí)行方法發(fā)生異常之后,連接關(guān)閉了,但是數(shù)據(jù)庫(kù)中遺留有活動(dòng)事務(wù)(dbcc opentran對(duì)應(yīng)的SessionId是sleeping狀態(tài)),于是就產(chǎn)生了阻塞。
關(guān)鍵是活動(dòng)事務(wù)會(huì)不定時(shí)自己消失,就有點(diǎn)詭異了,這是本文的重點(diǎn)。
這種機(jī)制跟連接池有關(guān):
當(dāng)應(yīng)用程序連接數(shù)據(jù)庫(kù)的時(shí)候開(kāi)啟了連接池,如果應(yīng)用程序調(diào)用了一個(gè)開(kāi)啟了事務(wù)操作的存儲(chǔ)過(guò)程,
當(dāng)發(fā)生異常的時(shí)候,有可能會(huì)出現(xiàn)數(shù)據(jù)庫(kù)連接關(guān)閉,而存儲(chǔ)過(guò)程中的事務(wù)既沒(méi)有提交,也沒(méi)有回滾的情況。
這種情況下就會(huì)產(chǎn)生“孤立事務(wù)”,也就是說(shuō),因?yàn)榇蜷_(kāi)事務(wù)的數(shù)據(jù)量連接斷掉了,而事務(wù)還處于活動(dòng)狀態(tài),
實(shí)際上開(kāi)啟連接池的情況下,數(shù)據(jù)庫(kù)連接的關(guān)閉,并不是物理上的關(guān)閉,而是將數(shù)據(jù)庫(kù)連接返回到連接池。
此時(shí)如果沒(méi)有外界的干預(yù),包括沒(méi)有對(duì)這個(gè)數(shù)據(jù)庫(kù)連接沒(méi)有被重用,或者這個(gè)連接沒(méi)有物理斷開(kāi),或者是沒(méi)有重啟應(yīng)用程序,或者沒(méi)有數(shù)據(jù)庫(kù)服務(wù)器,這個(gè)事務(wù)將一直持續(xù)下去。
因?yàn)榛顒?dòng)事務(wù)將阻塞其他Session對(duì)相關(guān)表的排他性訪(fǎng)問(wèn),所以就表現(xiàn)為阻塞。
如何判斷是否發(fā)生了連接池中的連接重用
首先,一個(gè)連接數(shù)據(jù)庫(kù)的過(guò)程中,有沒(méi)有重用連接池中的連接,在SQL Server中有哪些區(qū)別?
以ado.net為例,如果在連接字符串中加入pooling=false;則表示不啟用連接池.
如下,連續(xù)執(zhí)行兩次數(shù)據(jù)庫(kù)訪(fǎng)問(wèn),兩次數(shù)據(jù)庫(kù)訪(fǎng)問(wèn)均在連接字符串中加入了pooling=false;表示不啟用連接池