2016-01-11 64 views
0

我剛開始學習Go。當天的課程是將我的數據庫處理程序包裝在結構中以避免使用全局範圍變量。以爲我理解它到目前爲止,並希望延遲Close()方法,就像我以前那樣,以堆棧溢出結束。延遲結構sqlx.Close()以堆棧溢出結束

我找不到解釋爲什麼會發生這種情況,也沒有什麼解決方法。

這裏是關鍵代碼:

package exporter 

type DB struct { 
    *sqlx.DB 
    queriesExecuted int 
} 

func Open(dataSourceName string) *DB { 
    connection := sqlx.MustConnect("mysql", dataSourceName) 
    db := &DB{connection, 0} 
    return db 
} 

func (db *DB) Close() { 
    db.Close() // this is where the stack growth happens 
} 

func (db *DB) GetArticles() []oxarticle { 
    ... 
} 

package main 

func main() { 
    exporter := feedexporter.Open("root:[email protected]/feedexport") 
    defer exporter.Close() 

    articles := exporter.GetArticles() 
} 

一切正常,無延遲exporter.Close(),包括它結束在:

runtime: goroutine stack exceeds 1000000000-byte limit

fatal error: stack overflow

感覺如此不好關閉連接;)處理這個問題的方法是什麼?

回答

6

你在你的Close()方法觸發無限循環:

func (db *DB) Close() { 
    db.Close() // you're currently IN this exact method! 
} 

什麼你大概意思做的是調用一個已嵌入到您的自定義DB結構的sqlx.DB結構的Close()方法。我不太熟悉sqlx包,但是according to the documentation這種類型甚至沒有Close()方法。這是最有可能是因爲sqlx.DB實際上並不代表一個連接,但創建和透明地關閉連接的連接池:

A DB instance is not a connection, but an abstraction representing a Database. This is why creating a DB does not return an error and will not panic. It maintains a connection pool internally, and will attempt to connect when a connection is first needed.

documentation解釋深入如何處理這個連接池(重點煤礦):

By default, the pool grows unbounded, and connections will be created whenever there isn't a free connection available in the pool. You can use DB.SetMaxOpenConns to set the maximum size of the pool. Connections that are not being used are marked idle and then closed if they aren't required. To avoid making and closing lots of connections, set the maximum idle size with DB.SetMaxIdleConns to a size that is sensible for your query loads.

It is easy to get into trouble by accidentally holding on to connections. To prevent this:

  1. Ensure you Scan() every Row object
  2. Ensure you either Close() or fully-iterate via Next() every Rows object
  3. Ensure every transaction returns its connection via Commit() or Rollback()