Go语言 sql连接与连接池


原文链接: Go语言 sql连接与连接池

最大连接 包含4类 1. 已经建立的连接(正在使用) 2.空闲连接(使用完毕) 3. 新建连接(正在创建) 4. 未创建的连接

错误提示

packets.go:32: unexpected EOFpackets.go:118: write tcp 192.168.3.90:3306: broken pipe

上面都是错误都是go-sql-drive本身的输出,有的时候还会出现bad connection的错误。多请求几次后连接池会重新打开新连接这时候就没有问题了

db, _ = sql.Open("mysql", "rdswetec:FWkKYmmLtEbQzs#kG!vA4f!eYiClhuuu@tcp(192.168.0.18:3306)/adwetec_prod?charset=utf8")

// 连接池的实现关键在于设置最大连接数和设置最大空闲连接数其中:
//
// SetMaxOpenConns: 用于设置最大打开的连接数(默认值为0表示不限制)
// SetMaxIdleConns: 用于设置闲置的连接数
//
// 设置最大的连接数可以避免并发太高导致连接MYSQL出现"TOO MANY CONNECTIONS"的错误
// 设置闲置的连接数则当开启的一个连接使用完成后可以放在池里等候下一次使用

db.SetMaxOpenConns(2000)
db.SetMaxIdleConns(1000)

db.Ping()
// 如果保持一个空闲链接太长,则会出现出现网络连接的问题,类似下面错误: 
// unexpected EOF
// write tcp 192.168.3.90:3306: broken pipe
// 可以试着:db.SetMaxIdleConns(0)

}

连接池配置

配置连接池有两个的方法:

db.SetMaxOpenConns(1000)
设置打开数据库的最大连接数。该函数的默认设置是0,表示无限制。 包含正在使用的连接和连接池的连接。
如果你的函数调用需要申请一个连接,并且连接池已经没有了连接或者连接数达到了最大连接数。此时的函数调用将会被block,直到有可用的连接才会返回。设置这个值可以避免并发太高导致连接mysql出现too many connections的错误。

db.SetMaxIdleConns(100) 设置连接池中的保持连接的最大连接数。默认是2,
设置为0表示连接池不会保持释放连接池中的连接的连接状态:即当连接释放回到连接池的时候,连接将会被关闭。这会导致连接再连接池中频繁的关闭和创建。

对于连接池的使用依赖于你是如何配置连接池,如果使用不当会导致下面问题:

大量的连接空闲,导致额外的工作和延迟。
连接数据库的连接过多导致错误。
连接阻塞。
连接池有超过十个或者更多的死连接,限制就是10次重连。

大多数时候,如何使用sql.DB对连接的影响大过连接池配置的影响。这些具体问题我们会再使用sql.DB的时候逐一介绍。

掌握了database/sql关于数据库连接池管理内容,下一步则是使用这些连接,进行数据的交互操作啦。

连接池

只用sql.Open函数创建连接池,可是此时只是初始化了连接池,并没有创建任何连接。连接创建都是惰性的,只有当你真正使用到连接的时候,连接池才会创建连接。连接池很重要,它直接影响着你的程序行为。

连接池的工作原来却相当简单。当你的函数(例如Exec,Query)调用需要访问底层数据库的时候,函数首先会向连接池请求一个连接。如果连接池有空闲的连接,则返回给函数。否则连接池将会创建一个新的连接给函数。一旦连接给了函数,连接则归属于函数。函数执行完毕后,要不把连接所属权归还给连接池,要么传递给下一个需要连接的(Rows)对象,最后使用完连接的对象也会把连接释放回到连接池。

请求一个连接的函数有好几种,执行完毕处理连接的方式稍有差别,大致如下:

db.Ping() 调用完毕后会马上把连接返回给连接池。
db.Exec() 调用完毕后会马上把连接返回给连接池,但是它返回的Result对象还保留这连接的引用,当后面的代码需要处理结果集的时候连接将会被重用。
db.Query() 调用完毕后会将连接传递给sql.Rows类型,当然后者迭代完毕或者显示的调用.Clonse()方法后,连接将会被释放回到连接池。
db.QueryRow()调用完毕后会将连接传递给sql.Row类型,当.Scan()方法调用之后把连接释放回到连接池。
db.Begin() 调用完毕后将连接传递给sql.Tx类型对象,当.Commit()或.Rollback()方法调用后释放连接。

因为每一个连接都是惰性创建的,如何验证sql.Open调用之后,sql.DB对象可用呢?通常使用db.Ping()方法初始化:

`