fkm blog

software開発に関することを書いていきます

Goのdatabase/sqlパッケージでコネクションプールを使うには?

結論から先に言ってしまうと, sql.DB構造体がコネクションプールもってます. なので, あんまり考えることなさそう.

まずはドキュメントを読んでみる.

type DB

DB is a database handle representing a pool of zero or more underlying connections. It's safe for concurrent use by multiple goroutines.

DBはデータベースのハンドルで, 0個以上のコネクションプールを表すよ!
複数のgoroutineから同時に使っても大丈夫よ!

ドキュメントを読む限りでは大丈夫そうだけど, ホントにそう実装されてるか疑うクセをつけてソースを読んでみる. Open関数を見てみる.

func Open(driverName, dataSourceName string) (*DB, error) {
    driveri, ok := drivers[driverName]
    if !ok {
        return nil, fmt.Errorf("sql: unknown driver %q (forgotten import?)", driverName)
    }
    db := &DB{
        driver:   driveri,
        dsn:      dataSourceName,
        openerCh: make(chan struct{}, connectionRequestQueueSize),
        lastPut:  make(map[*driverConn]string),
    }
    db.freeConn = list.New()
    db.connRequests = list.New()
    go db.connectionOpener()
    return db, nil
}

driverを名前で引いてきて, sql.DBオブジェクト作って, freeConnとconnRequestsを作ってdriver経由でコネクションを作る. 確かにプール持ってる.

そんな理由で, Close()関数にはこんなことが書かれてる.

func (*DB) Close

It is rare to Close a DB, as the DB handle is meant to be long-lived and shared between many goroutines.

DBを閉じるのってレアケースだよ. だってDBハンドルは長い間生存して、多くのgoroutine間で共有されるものだからね

ということで, サーバーサイドで使う時は, Listenする前に1つ作って, 終了時にClose()を呼ぶ というのでよさそうな感.