2016-01-11 31 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()