尽管database/sql包提供了连接池速率限制和超时,调整默认值以更好地适应数据库配置通常很重要。当你在微服务上进行水平扩展并且不希望保持与数据库的过多活动连接时,这可能很重要。

实践

建立 pools.go:

package pools

import (
    "database/sql"
    "fmt"
    "os"

    _ "github.com/go-sql-driver/mysql"
)

func Setup() (*sql.DB, error) {
    db, err := sql.Open("mysql",
        fmt.Sprintf("%s:%s@/gocookbook?parseTime=true", os.Getenv("MYSQLUSERNAME"), os.Getenv("MYSQLPASSWORD")))
    if err != nil {
        return nil, err
    }

    // 仅开放24个连接
    db.SetMaxOpenConns(24)

    // MaxIdleConns不可以比SetMaxOpenConns的值小 否则会将SetMaxOpenConns的值作为默认值
    db.SetMaxIdleConns(24)

    return db, nil
}

建立 timeout.go:

package pools

import (
    "context"
    "time"
)

// ExecWithTimeout 使用context来实现超时
func ExecWithTimeout() error {
    db, err := Setup()
    if err != nil {
        return err
    }

    ctx := context.Background()

    // 我们希望立刻超时
    ctx, can := context.WithDeadline(ctx, time.Now())

    // 在函数完成后调用cancel
    defer can()

    // 以当前context为参数
    _, err = db.BeginTx(ctx, nil)
    return err
}

建立 main.go:

package main

import "github.com/agtorre/go-cookbook/chapter5/pools"

func main() {
    if err := pools.ExecWithTimeout(); err != nil {
        panic(err)
    }
}

这会输出:

panic: context deadline exceeded
goroutine 1 [running]:
main.main()
/go/src/github.com/agtorre/gocookbook/chapter5/pools/example/main.go:7 +0x4e
exit status 2

说明

限制数据库连接池深度非常有用,这将保护数据库不会超载,不过更重要的是考虑context在这里的使用。如果你强制限制一定数量的连接并严格的基于上下文的超时,就像我们在示例中所做的那样,在某些情况下,会出现有一些请求经常超时并试图建立过多连接导致程序重载。

这个新加入sql包的函数使得包括查询在内的请求共享超时更加简单。

使用全局配置对象传递给Setup()函数是有意义的,当然我们在这里使用的是环境变量。

最后编辑: kuteng  文档更新时间: 2021-01-03 15:03   作者:kuteng