There are a couple of good resources you can use here, the first is just about the best reference for using Go with a RDBMS:<p><a href="http://go-database-sql.org/" rel="nofollow">http://go-database-sql.org/</a><p>The second speaks of database connections:<p><a href="http://jmoiron.net/blog/gos-database-sql/" rel="nofollow">http://jmoiron.net/blog/gos-database-sql/</a><p>The general approach:<p>1. Use a single DB connection, it will pool automatically<p>2. Use this pattern for all single row queries:<p><pre><code> err = db.QueryRow(`...`, ...).Scan(&...)
if err == sql.ErrNoRows {
// Handle no rows
} else if err != nil {
// Handle actual error
}
// All fine
</code></pre>
3. Use this pattern for all multi-row queries where you want to return a slice of structs containing the row values. Note that it is fine to call rows.Close() as soon as possible in addition to deferring it, defer takes care of handling it whenever something goes wrong and the explicit call returns the connection as soon as possible:<p><pre><code> rows, err := db.Query(`...`, ...)
if err != nil {
// Handle connection or statement error
}
defer rows.Close()
things := []rowStruct{}
for rows.Next() {
thing := rowStruct{}
err = rows.Scan(
&thing.id,
&thing.value,
)
if err != nil {
// Handle row parsing error
}
things = append(things, thing)
}
err = rows.Err()
if err != nil {
// Handle any errors within rows
}
rows.Close()
</code></pre>
4. Use transactions as serial things, if you need to call another query whilst in a loop where you can't rows.Close(), then read the rows into a slice and range over the slice. You must <i>never</i> have two queries running in the same transaction... so code to do one thing before you do another, and be mindful of this if you are passing the transaction to other funcs.<p>An extra bit of info:<p>5. defer doesn't just have to be used to call rows.Close(), if you want to know when things happen you can wrap the defer and log:<p><pre><code> rows, err := db.Query(`...`,...)
if err != nil {
// Handle connection or statement error
}
defer func() {
log.Println(`Closing rows`)
rows.Close()
}()
</code></pre>
On which point, beware there are some theoretically uncaught errors, for example tx.Rollback() can return an error <a href="http://golang.org/pkg/database/sql/#Tx.Rollback" rel="nofollow">http://golang.org/pkg/database/sql/#Tx.Rollback</a> but if you have called it using defer tx.Rollback() after creating a transaction you'll never know. I <i>hope</i> that the only reason that might error is that something has already ended the transaction, but there is definitely scope for deferred finalisation within a func to cause errors that you might miss and it's worth considering the pattern above if you have any mysterious behaviour going on.