我們在使用MySQL服務(wù)的時候,正常情況下,mysql的設(shè)置的timeout是8個小時(28800秒),也就是說,如果一個連接8個小時都沒有操作,那么mysql會主動的斷開連接,當(dāng)這個連接再次嘗試查詢的時候就會報個"MySQL server has gone away"的誤,但是有時候,由于mysql服務(wù)器那邊做了一些設(shè)置,很多情況下會縮短這個連接timeout時長以保證更多的連接可用。有時候設(shè)置得比較變態(tài),很短,30秒,這樣就需要客戶端這邊做一些操作來保證不要讓mysql主動來斷開。
查看mysql的timeout
使用客戶端工具或者M(jìn)ysql命令行工具輸入show global variables like '%timeout%';就會顯示與timeout相關(guān)的屬性,這里我用Docker模擬了一個測試環(huán)境。

wait_timeout:服務(wù)器關(guān)閉非交互連接之前等待活動的秒數(shù),就是你在你的項目中進(jìn)行程序調(diào)用
interactive_timeout: 服務(wù)器關(guān)閉交互式連接前等待活動的秒數(shù),就是你在你的本機(jī)上打開mysql的客戶端,比如cmd
使用pymysql進(jìn)行查詢
我在數(shù)據(jù)庫里隨便創(chuàng)建了一個表,插入兩條數(shù)據(jù)

我使用pymysql這個庫對其進(jìn)行查詢操作,很簡單

可以正確的得到結(jié)果
(1, 'yang', 18) (2, 'fan', 16)
連接超時以后的查詢
上面可以正常得到結(jié)果是由于當(dāng)創(chuàng)建好一個連接以后,就立刻進(jìn)行了查詢,此時還沒有超過它的超時時間,如果我sleep一段時間,看看什么效果。

這里進(jìn)行了兩次查詢,因為我把mysql的wait_timeout設(shè)置了30秒,所以我在第一次查詢之后停了31秒,目的讓mysql服務(wù)主動的和我剛才創(chuàng)建的連接斷開,得到的結(jié)果是

可以看到在停了31秒鐘以后,再次使用該連接進(jìn)行查詢將拋出2013, 'Lost connection to MySQL server during query'錯誤。
解決辦法
解決的方法有兩種,既然這里的超時是由于在規(guī)定時間內(nèi)沒有任何操作導(dǎo)致mysql主動的將連接關(guān)閉,pymysql的connection對象有一個ping()方法,可以檢查連接是否有效,在每次執(zhí)行查詢操作之前先執(zhí)行一下ping()方法,該方法默認(rèn)的有個reconnect參數(shù),默認(rèn)是True,如果失去連接了會重連。

我曾嘗試使用另外一個線程不停來執(zhí)行ping()操作,但是當(dāng)我這樣做以后連接就會丟失,之后的操作就不能進(jìn)行了。這個問題我再研究研究。

還有一種方法是使用連接池,連接池中保持著指定數(shù)量的可用連接,每次重新獲取一個有效的連接進(jìn)行查詢操作,pymysql本身不具有連接池功能,需要借住DBUtils

這種方式雖然可以正確的獲取結(jié)果,但是實際的項目中并不會這么使用,而是在執(zhí)行完查詢語句以后要將connection關(guān)閉,注意這里的關(guān)閉并不是真正的關(guān)閉,而只是將連接返回給連接池讓其他人使用.
