之前写了一个go脚本,每隔五分钟读取一次nginx日志,把访问的ip信息抓取出来并写入数据库,跑起来没有问题,但是每过四天,数据库就挂了,脚本也异常退出了,检查发现数据库的连接数一直在增加,go的数据库连接部分如下:
func MsgToDB(msg request msg) {
stmt, err := GetConn().Prepare("insert visit_monitor set remote_addr=?, Request =?, request_time=?, status=?, http_user_agent=?")
checkErr(err)
res, err := stmt.Exec(msg.Remote_addr, msg.Request, msg.Request_time, msg.Status, msg.Http_user_agent)
checkErr(err)
defer stmt. Close () // 这里设置了资源释放
if err == nil {
id, err := res.LastInsertId()
checkErr(err)
fmt.Println("msg num is:", id)
}
}
func GetConn() * sql .DB {
db, _ := sql.Open(" mysql ", "root:***@tcp(xxx.xxx.xxx.xxx:3306)/xue?charset=utf8")
return db
}
在MsgToDB()方法中已经使用“ defer stmt.Close()”做了资源释放,但是查看数据库的连接数还是一直在增长:
mysql> show status like 'Threads%';
+-------------------+-------+
| Variable_name | Value |
+-------------------+-------+
| Threads_cached | 70 |
| Threads_connected | 400 |
| Threads_created | 74 |
| Threads_running | 1 |
+-------------------+-------+
4 rows in set (0.00 sec)
其实原因很简单,database/sql本身是带线程池的,golang团队已经封装很好了,原因是我从网上直接找了一段全局获得GetConn()的代码直使用了,GetConn()确实可以全局返回一个*sql.DB,但是每次都返回一个新的,相当于每次都创建了一套连接,改造方案如下:
var db *sql.DB
func init() {
db, _ = sql.Open("mysql", "root:****@tcp(192.168.0.4:3306)/xue?charset=utf8")
db.SetMaxOpenConns(10)
db.SetMaxIdleConns(10)
db. Ping ()
}
func MsgToDB(msg Requestmsg) {
stmt, err := db.Prepare("insert visit_monitor set remote_addr=?, request=?, request_time=?, status=?, http_user_agent=?")
checkErr(err)
res, err := stmt.Exec(msg.Remote_addr, msg.Request, msg.Request_time, msg.Status, msg.Http_user_agent)
checkErr(err)
defer stmt.Close() // 这里设置了资源释放
if err == nil {
id, err := res.LastInsertId()
checkErr(err)
fmt.Println("msg num is:", id)
}
}
// 废弃此方法
//func GetConn() *sql.DB {
// db, _ := sql.Open("mysql", "root:***@tcp(xxx.xxx.xxx.xxx:3306)/xue?charset=utf8")
// return db
//}