Go鏈接MySql數據庫too many connections

Go中鏈接數據庫的鏈接池:當你須要和數據庫通訊時,就會從鏈接池裏面取出一個鏈接,和數據庫交互。使用完的閒置的鏈接會回到鏈接池,等待下一次的調用。若是鏈接池裏面沒有閒置的鏈接,會自動建立一個新的鏈接出來。其中有一段:php

An sql.Row returns the connection when Scan() is called, sql.Rows returns either when Close() is called or all rows have been iterated over with Next(), and sql.Tx will return when Commit or Rollback() are called. If you forget to completely iterate an sql.Rows and you forget to Close it, that connection will never go back to the pool.golang

       從上面能夠看到,sql.Row若是不遍歷完或者直接調用Close()方法,執行此次查詢的鏈接就會一直存在!當鏈接池裏的可用鏈接用光後,就開始建立新的鏈接。這就是爲何調用SetMaxOpenConns沒有用的緣由,由於這個函數只是設置鏈接池裏的鏈接數而已!若是由於不及時釋放鏈接而讓鏈接池幹掉了,仍是會不斷的建立新的鏈接,直到用光MySql全部的鏈接,報錯。明白之後,在全部調用DB.Query的函數里加上了:web

defer row.Close()

        這樣查詢鏈接就能在函數結束或者異常的狀況下被關閉,就不會持續建立新的鏈接了。滿覺得這樣就能夠解決問題了,可是服務器運行了之後,過段時間仍然會出現相同的錯誤。在phpMyadmin裏的監控頁面,能夠看到程序運行之後MySql的鏈接數猛增。問題又變得無解了,只能從新一行行檢查代碼。
sql

        Go中的函數能夠有多個返回值,使用下劃線能夠忽略不須要的返回值:
數據庫

_, err := m.DB.Query("sql")

        程序中update和del之類的sql語句不須要返回值,就直接忽略了。猜測這樣也是無法釋放鏈接的,由於即便你不接受返回值,不表明這個變量就不存在了。也就是說返回的sql.Row仍是存在的,只是你沒有接收而已。沒接收,就更談不上釋放鏈接了,因此最後產生了大量的鏈接繼續報錯。回頭看看那篇文章,看到這麼一段:
服務器

Ping and Exec will release the connection right before returning, but the others will pass ownership of the connection to the result, whether that's an sql.Row, sql.Rows, or sql.Tx.app

        也就是說Ping和Exec方法在調用完以後,會自動釋放鏈接。把代碼中全部不須要返回值的語句改爲由Exce方法執行,go run 一下,ok,鏈接數終於正常了!
函數

        問題是解決了,總起來之後要注意一下的東西:
ui

  • 程序鏈接數據庫會有鏈接泄漏的狀況,須要及時釋放鏈接url

  • Go sql包中的Query和QueryRow兩個方法的鏈接不會自動釋放鏈接,只有在遍歷完結果或者調用close方法纔會關閉鏈接

  • Go sql中的Ping和Exec方法在調用結束之後就會自動釋放鏈接

  • 忽略了函數的某個返回值不表明這個值就不存在了,若是該返回值須要close纔會釋放資源,直接忽略了就會致使資源的泄漏。

  • 有close方法的變量,在使用後要及時調用該方法,釋放資源

相關文章
相關標籤/搜索